虚拟列表可以用来渲染有大量数据的列表,并且不有有任何的性能问题。并且,它和所有的Framework7组件都是兼容的,包括搜索栏、无限滚动、下拉刷新、滑动删除和可排序列表。
虚拟列表打HTML结构非常简单,他和常见的 列表 或者 多媒体列表只有一个区别,你必须把它的内容设置为空的。
- <!-- Virtual List -->
- <div class="list-block virtual-list">
- <!-- 内容置空 -->
- </div>
其中:
virtual-list
- 在使用虚拟列表的容器上增加这个类
现在,当我们有了列表的HTML,我们下一步是初始化它。我们需要用到这些App方法:
myApp.virtualList(listBlockContainer, parameters) - 使用parameters参数初始化虚拟列表
比如:
- var myList = app.virtualList('.list-block', {
- items: [1,2,3,4],
- height: 44
- });
下面是所有的初始化参数:
参数 | 类型 | 默认值 | 说明 |
---|---|---|---|
items | array | 包含列表条目的数组 | |
rowsBefore | number | 在当前屏幕滚动位置之前需要渲染的条目数。默认是两倍当前屏幕大小需要的数量。(译者注:也就是说,假设你的屏幕是320px高,每一个条目是40px,那么当前屏幕上方会有(320/40*2) == 16条),加上当前屏幕中的8条和屏幕下方的8条,总共在DOM中存在32个条目)。 | |
rowsAfter | number | 在当前屏幕滚动位置之后需要渲染的条目数。默认是当前屏幕大小需要的数量。(译者注:参加上面的说明)。 | |
cols | number | 1 | 每一行需要的条目数。如果你用了动态的高度,这个参数是不兼容的。 |
height | number or function(item) | 44 | 如果是 数字,那么它是每一个条目的px高度。如果是 函数,那么它应该返回条目的高度。 |
template | string or function | Template7 字符串模板,或者是Template7 编译后的模板,用来渲染单个条目。这个模板应该有一个条目的完整HTML结构,包括外面的 <li></li> 容器。 | |
renderItem | function(index, item) | 这个可选方法用来自定义渲染条目的HTML。它是用来代替 tamplate 参数的。 | |
dynamicHeightBufferSize | number | 1 | This parameter allows to control buffer size on Virtual Lists with dynamic height (when height parameter is function) as a buffer size multiplier |
cache | boolean | true | 启用/禁用已经渲染的条目的DOM缓存。启用的情况下,每一个条目都只会被渲染一次,后续都是对DOM的操作。如果你的条目中需要保存一些用户的操作(比如表单或者滑动删除)或者修改,那么这个参数是很有用的。 |
updatableScroll | boolean | 当前是否在滚动的时候会更新滚动条并触发滚动事件。默认情况下对所有iOS 8 以下的设备都是false。 | |
搜索 | |||
searchByItem | function(query, index, item) | 搜索栏用的搜索方法,它接收三个参数:搜索词,条目的序号和条目自身。如果一个条目符合结果,你应该返回 true ,否则返回false。 | |
searchAll | function(query, items) | 搜索栏用到的搜索方法,它接受两个参数:搜索词,和包含所有条目的数组。你需要自己遍历并返回匹配的条目。 | |
回调 | |||
onItemBeforeInsert | function(list, item) | 回调函数,当条目被插入到虚拟列表的 document fragment 之前执行。 | |
onBeforeClear | function(list, fragment) | 回调函数,当前列表的DOM元素被删除并替换成新的 document fragment 之前执行。 | |
onItemsBeforeInsert | function(list, fragment) | 回调函数,当前列表的DOM元素被删除之后,准备替换成新的 document fragment 之前执行。 | |
onItemsAfterInsert | function(list, fragment) | 回调函数,新的 document fragment 插入之后执行。 |
当我们初始化完成之后,我们就有一个存储了虚拟列表实例的变量(比如上面例子中的 myList
变量),这个实例有很有有用的方法和属性:
属性 | |
---|---|
myList.items | 包含所有条目的数组 |
myList.filteredItems | 所有过滤之后的条目(在执行了 ".filterItems" 方法之后) |
myList.domCache | 条目的DOM缓存 |
myList.params | 初始化时传递的参数 |
myList.listBlock | 虚拟列表的容器的 Dom7 实例 |
myList.pageContent | 当前页面的 "page-content" 容器的 Dom7 实例 |
myList.currentFromIndex | 当前被渲染的第一个条目的序号 |
myList.currentToIndex | 当前被渲染的最后一个条目的序号 |
myList.reachEnd | 布尔属性,如果当前的最后条目是否是所有条目中的最后一个。 |
方法 | |
myList.filterItems(indexes); | 过滤当前列表,只显示传入的序号指定的条目。 |
myList.resetFilter(); | 关闭过滤,并再次显示所有的条目 |
myList.appendItem(item); | 增加条目 |
myList.appendItems(items); | 增加多个条目(数组) |
myList.prependItem(item); | 在前面增加条目 |
myList.prependItems(items); | 在前面增加多个条目(数组) |
myList.replaceItem(index, items); | 把指定序号的条目换成一个新的条目 |
myList.replaceAllItems(items); | 把所有的条目都换成新的 |
myList.moveItem(oldIndex, newIndex); | 把一个条目从 oldIndex 换到 newIndex |
myList.insertItemBefore(index, item); | 在指定的序号前插入一个条目 |
myList.deleteItem(index); | 删除指定序号的条目 |
myList.deleteItems(indexes); | 删除指定的序号数组的条目 |
myList.deleteAllItems(); | 删除所有条目 |
myList.clearCache(); | 删除DOM缓存 |
myList.destroy(); | 销毁实例,解除所有事件绑定 |
myList.update(); | 更新列表。会重新计算列表的大小,并重新渲染 |
myList.scrollToItem(index); | 滚动到指定位置 |
最简单的一种情况,我们不需要用模板来渲染条目(没有 template
和 renderItem
参数),并且我们也不需要复杂的逻辑,我们直接在 items
参数中传入了HTML字符串:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with plain HTML items
- items: [
- '<li class="item-content"><div clas="item-inner"><div class="item-title">Item 1</div></div></li>',
- '<li class="item-content"><div clas="item-inner"><div class="item-title">Item 2</div></div></li>',
- '<li class="item-content"><div clas="item-inner"><div class="item-title">Item 3</div></div></li>',
- //...
- '<li class="item-content"><div clas="item-inner"><div class="item-title">Item 1000</div></div></li>'
- ]
- });
但是大部分情况下,我们需要有一些过滤和渲染的逻辑,或者我们会从一个JSON字符串中加载数据。这种情况下,我们在 items
参数中传入数据,然后使用 Template7 template
参数或者使用 renderItem
自定义一个渲染函数。
使用Template7模板:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1',
- picture: 'path/to/picture1.jpg'
- },
- {
- title: 'Item 2',
- picture: 'path/to/picture2.jpg'
- },
- // ...
- {
- title: 'Item 1000',
- picture: 'path/to/picture1000.jpg'
- },
- ],
- // Template 7 template to render each item
- template: '<li class="item-content">' +
- '<div class="item-media"><img src="{{picture}}"></div>' +
- '<div class="item-inner">' +
- '<div class="item-title">{{title}}</div>' +
- '</div>' +
- '</li>'
- });
使用自定义的渲染函数:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1',
- picture: 'path/to/picture1.jpg'
- },
- {
- title: 'Item 2',
- picture: 'path/to/picture2.jpg'
- },
- // ...
- {
- title: 'Item 1000',
- picture: 'path/to/picture1000.jpg'
- },
- ],
- // Custom render function to render item's HTML
- renderItem: function (index, item) {
- return '<li class="item-content">' +
- '<div class="item-media"><img src="' + item.picture + '"></div>' +
- '<div class="item-inner">' +
- '<div class="item-title">' + item.title + '</div>' +
- '</div>' +
- '</li>';
- }
- });
如果我们想使用搜索栏,我们必须在初始化的事后传入一个 searchAll
或者 searchByItem
参数:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1',
- picture: 'path/to/picture1.jpg'
- },
- {
- title: 'Item 2',
- picture: 'path/to/picture2.jpg'
- },
- // ...
- {
- title: 'Item 1000',
- picture: 'path/to/picture1000.jpg'
- },
- ],
- // search all items, we need to return array with indexes of matched items
- searchAll: function (query, items) {
- var foundItems = [];
- for (var i = 0; i = 0) foundItems.push(i);
- }
- // Return array with indexes of matched items
- return foundItems;
- }
- });
和上面功能相同,但是使用 searchByItem
参数:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1',
- picture: 'path/to/picture1.jpg'
- },
- {
- title: 'Item 2',
- picture: 'path/to/picture2.jpg'
- },
- // ...
- {
- title: 'Item 1000',
- picture: 'path/to/picture1000.jpg'
- },
- ],
- // search item by item
- searchByItem: function (query, index, item) {
- // Check if title contains query string
- if (item.title.indexOf(query.trim()) >= 0) {
- return true; //item matches query
- }
- else {
- return false; //item doesn't match
- }
- }
- });
如果我们的条目并不是都一样高的,那么我们可以通过 height
参数传入一个函数而不是数字来制定高度:
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1',
- picture: 'path/to/picture1.jpg'
- },
- {
- title: 'Item 2'
- },
- {
- title: 'Item 3',
- picture: 'path/to/picture3.jpg'
- },
- // ...
- {
- title: 'Item 1000'
- },
- ],
- // Item template
- template: '...',
- // Height function
- height: function (item) {
- if (item.picture) return 100; //item with picture is 100px height
- else return 44; //item without picture is 44px height
- }
- });
注意,JS并不是直接设定了你的条目的高度,所以请确保你的条目确实有指定的高度。你可能依然需要在CSS中设置,或者在 template
或者 renderItem
参数中通过 设置"style"属性来设置高度。
注意动态高度和 cols
参数是不兼容的!
如果我们需要增加、删除、替换或者移动条目,我们需要使用虚拟列表的相关方法:
- // Initialize List
- var myList = myApp.virtualList('.list-block.virtual-list', {
- // Array with items data
- items: [
- {
- title: 'Item 1'
- },
- {
- title: 'Item 2'
- },
- // ...
- {
- title: 'Item 1000'
- }
- ],
- // Item template
- template: '...',
- });
- // Append Item
- myList.appendItem({
- title: 'Item 1001'
- });
- // Append multiple items when clicking on some button
- $('.button.append-items').on('click', function () {
- // Append multiple items by passing array with items
- myList.appendItem([
- {
- title: 'Item 1002'
- },
- {
- title: 'Item 1003'
- },
- {
- title: 'Item 1004'
- }
- ]);
- });
- // Replace First Item
- myList.replaceItem(0, {
- title: 'New Item 1'
- });
- // Show only first 10 items when clicking on button
- $('.button.show-first-10').on('click', function () {
- // We need to pass array with indexes of items to show
- myList.filter([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]);
- });
- // Reset filter
- $('.button.reset-filter').on('click', function () {
- myList.resetFilter();
- });
- // Insert new item before 1st and 2nd:
- myList.insertItemBefore(1, {
- title: 'Item 1.5'
- });
注意,如果你使用上面这些方法来操作虚拟列表,你传入的每一个条目的格式必须和你在 items 参数中指定的是一样的。