Virtualize虚拟列表
Virtual Scrolling虚拟滚动/Virtual List虚拟列表是前端一种列表加载技术,他模拟真实的容器滚动条,并支持在数据充足的情况下无限滚动和无限渲染,即便如此却很少消耗内存和性能,因为虚拟列表仅仅是渲染用户视线所及的部分,用户看不到的部分或者不关心的部分并不会被渲染。虚拟列表、懒加载和分页加载是三种长列表解决方案,各有优劣。
前言
虚拟滚动列表和真实滚动列表,使用相同的滚动条,但是他们渲染的内容是有差别的。真实滚动条的滚动距离与真实渲染直接相关,渲染的节点越多,可滚动的距离越长;而虚拟滚动的内容容器是由部分渲染节点,加上内容容器的translate偏移值伪造出了滚动条,虽然滚动距离很长,但是实际上渲染的节点很少,仅仅是铺满视线所及的区域。
因为虚拟滚动列表渲染的节点比较少,所以可以大大较少内存和性能消耗,提高加载速度;对于大型数据列表,在不分页前提下,使用虚拟滚动列表是比较科学的解决方案。
普通参数
参数名 | 值类型 | 默认值 | 说明 |
---|---|---|---|
axis | 'x'/'y' | 'y' | 滚动方向 |
classes | string/string[] | '' | 对外容器添加样式名 |
size | number | 0 | 预估项目尺寸,高度还是宽度依据axis值而定,如果0将转换为页面行高数值28px(2.8rem) |
spill | number | 2 | 首尾外溢缓冲的项目个数 |
names | object | {wrap:'div',list:'div',cont:'div',item:'section'} | 如果有模块自动创建节点,设置的节点名 |
index | number | 0 | 初始化后第一项显示的索引 |
dynamic | boolean | true | 项目尺寸是否是动态可变的,默认true |
content | any | '' | 数据源,写法同getContent函数 |
contType | any | '' | 数据类型,写法同getContent函数 |
contData | object | {} | 请求数据时发送的数据,写法同getContent函数 |
ajax | object | {} | 请求数据时调用ajax函数时的参数 |
tplStr | string | '' | 模版字符串,其中可能会用到{{和}},当然需要看使用了哪个tplEng |
tplEng | function | null | 模板引擎,默认使用renderTpl函数作为模板引擎 |
等待函数参数
除了通用的b4Init
等待函数,还包含如下专属等待函数。这些等待函数也属于模块参数的一部分。
- b4Append:添加数据和节点前执行,应该返回一个
Promise
,如果没有resolve则停止执行;如果有resolve但是没有传值则按原来流程执行;如果有resolve并且传递一个值,则最终添加数据和节点将以新值为准。该函数参数如下:- data:新数据,来自append方法中对新数据处理后的数据数据
- b4UpdateItem:更新某项数据前执行,应该返回一个
Promise
,如果没有resolve则停止执行;如果有resolve但是没有传值则按原来流程执行;如果有resolve并且传递一个值,则最终添加数据和节点将以新值为准。该函数参数如下:- data:新数据,来自updateItem方法中对旧数据处理后的新数据
- b4Clear:清理所有数据前执行,应该返回一个
Promise
,如果没有resolve或有resolve但是没传值或传false则停止执行;如果有resolve并且传递true
值,则执行清除方法。该函数无参数。
监听事件
事件监听也可以叫做执行钩子函数,当某事件被触发将执行用户自定义的钩子函数,在模块的创建到销毁的生命周期中,除了通用的ready、launch、init、reset、destroy、error等事件,本模块还支持以下专属事件。
- append:新增数据后执行,在模块参数中写作
onAppend
,该事件参数如下:- data:新数据,来自append方法中对新数据处理后的数据数据
- updateItem:更新某项数据后执行,在模块参数中写作
onUpdateItem
,该事件参数如下:- data:新数据,来自updateItem方法中对旧数据处理后的新数据
- rendered:完成渲染后执行,在模块参数中写作
onRendered
,该事件参数如下:- data:渲染完成后的数据,该数据为一个对象,属性如下:
- startIdx:本次渲染的起始索引
- endIdx:本次渲染的结束索引
- nodes:临时节点,为节点数组
- scrollVal:滚动条卷去的尺寸
- offsetVal:列表translate偏移值
- wrapSize:内容器的尺寸
- data:渲染完成后的数据,该数据为一个对象,属性如下:
- getCont:获得数据之后执行,在模块参数中写作
onGetCont
,该事件参数如下:- data:刚获得的数据,数据为一个对象,包含content和source属性,content的值是一个数组将被添加到变量this.content中,source的值是原始数据
- exhausted:所有数据被渲染了之后执行,在模块参数中写作
onExhausted
,该事件参数如下:- data:即this.content变量,此时this.content中的每一项都被渲染了一遍
- toStart:滚动到头之后执行,在模块参数中写作
onToStart
,该事件无参数 - toEnd:滚动到尾之后执行,在模块参数中写作
onToEnd
,该事件无参数 - clear:清除后执行,在模块参数中写作
onClear
,该事件无参数
操作方法
除了通用的init、destroy、reset、update等方法,本模块还支持以下专属方法。
- append:新增数据,该方法参数如下:
- data:新数据,写法同
getContent
函数的第一个参数 - cb:回调函数,回调函数支持一个参数即新数据。
- data:新数据,写法同
- updateItem:更新某项数据,该方法参数如下:
- data:新数据,为一个对象,包含的属性如下:
- content:新值,新值可以是一个节点、一个字符串、一个数字或一个数据对象
- index:要更新的项目索引
- override:是否需要覆盖原数据,默认true即覆盖
- cb:回调函数,回调函数支持一个参数即新数据。
- data:新数据,为一个对象,包含的属性如下:
- scrollTo:跳转项目,该方法参数如下:
- index:跳转到指定项目的索引
- cb:回调函数,回调函数支持一个参数即跳转索引。
- toStart:跳转到头部,该方法无参数
- toEnd:跳转到尾部,该方法无参数
简单使用
我们使用Mockjs
模拟列表数据,将数据传入参数content
即可。
- 输出
- HTML
- JS
-
-
-
new ax.Virtualize('#virt02',{ content:Array(1000).fill(null).map((k,i)=>`${i}-${Mock.mock('@name')}`), });
水平滚动
默认为垂直方向的滚动,如果有必要可通过参数axis
设置水平滚动,即axis:'x'
。
- 输出
- HTML
- JS
-
-
-
new ax.Virtualize('#virt10',{ content:Array(1000).fill(null).map((k,i)=>`${i}-${Mock.mock('@name')}`), axis:'x', });
基本操作
本示例演示常用的操作方法。
- 输出
- HTML
- JS
-
-
-
let ins = new ax.Virtualize('#virt03',{ content:Array(1000).fill(null).map((k,i)=>`${i}-${Mock.mock('@name')}`), }); btn01.onclick = ()=>{ ins.append({content:Array(500).fill(null).map((k,i)=>`<i class="_c-error">${i}</i>`)}); } btn02.onclick = ()=>{ for(let k of ins.nodes){ ins.updateItem({ index:k.index, content:`<i class="_c-succ">${Mock.Random.cparagraph(1,8)}</i>` }); } } btn03.onclick = ()=>{ ins.clear(); } btn04.onclick = ()=>{ ins.scrollTo(~~(Math.random()*ins.content.length)); }