背景:项目中使用element-ui组件,项目中存在多处列表、下拉列表、下拉树包含大量数据的情况(万级)。
问题:在全量加载数据时,明显感受到页面的卡顿,延迟约3-10s不等,偶尔会导致浏览器内存炸裂,直接页面崩溃。
思路:在项目中的主要列表中,已经使用umy-table控件,支持虚拟滚动加载数据,性能有所提升。由于umy-table只支持表格控件,希望将这一思路用于select和项目封装的select-tree控件。
原理:
虚拟滚动的原理可以大致总结如下:(针对每一项高度fix的情况)
a. 只加载视口中的数据。
b. 已知每一项的高度,已知所有项的条目数,可知应该展示的总高度。
c. 通过scroll事件监听到滚动位置,计算出当前应该展示的数据,将数据塞入到展示的list中。
大致实现如下:
列表
固定每一项的高度,将visibaleData作为渲染el-tree的数据。 visibleData在初始化数据时通过原有treeData的数据进行截取,el-tree的容器的高度除以每一项的高度,得到应该在可是范围展示的记录条数,然后按照索引赋值对应的数据给visibleData。
后续在滚动时,更新visibleData,通过scrollTop除以每一项的高度,得到已经滚动过去了多少项,以此索引作为此次要加载的第一个数据,然后加上要显示的条目,既可展示对应滚动区域的数据。通过transform:translateY(offsetpx)来设置scrollTop偏移量,将渲染数据一直保持在可视范围。
给树形结构外层加一个wrapper,设置position为relative,并给定高度。
在wrapper中添加一个position为absolut的div,用于给定最大高度(所有数据的条数*每条高度)撑开tree容器,出现滚动条。
el-tree设置为absolute定位。
树
上述的实现主要是用于长列表,对于树形结构还需要进行如下的改造。
- 拍平树结构的数据
- 将所有子节点都拉到最外层,通过visible来计算是否展示
需要重写el-tree的dom结构
- 将所有子节点都拉到最外层,通过visible来计算是否展示