目录
1 使用场景
2 小插曲
3 虚拟列表渲染实现原理
4 代码实现
1 使用场景
在做EMBP项目时,有个模板新建的需求,需要点击获取子任务时获取所有的子任务,当时有的数据比较大,会有几百条的情况,此时接口请求变得很慢(这个后端做了优化),但是由于数据较多,前端渲染起来特别慢,最后通过度哥,学习了下前端渲染机制,最终通过虚拟列表渲染在前端做了优化。
2 小插曲
在此期间对前端的事件执行进行了学习,更好的了解了事件的执行顺序及时机。如下图,学习后发现可以通过添加定时器的方式来计算dom的渲染时间
在获取到数据后执行
let date1 = new Date();// 数据获取后执行
setTimeout(()=>{//setTimeout是一个宏任务 会等待ui渲染完成后执行
let data2 = new Date();// dom渲染后执行
},0)
3 虚拟列表渲染实现原理
(1)通过一条数据的高度及所有数据的长度获取到所有数据的高度(暂叫h1),在需要使用虚拟列表的同级地方添加一个div,高度设置成h1,
(2)在需要添加虚拟列表的dom中,将高度设置成其对应可视区的高度(暂叫h2)
(3)给需要添加虚拟列表的dom添加一个父级,将其高度设置成h2
(4)通过(1)来给对应可视区设置滚动,通过(3)来给虚拟列表添加定位,然后在滚动时,修改虚拟列表的top来实现虚拟列表永远出现在可视区内。
4 代码实现
(1)对应dom代码片段
<div class="list_view" ref="listView" @scroll="handleScroll" style="height:530px;overflow-y:auto;position: absolute;width:100%;z-index:9999;">
<!-- 表格内容 -->
<el-table :data="showList" ref="content" class="list_view_content" style="height:530px;position: absolute;width:100%;" :style="{top:scrollTop + 'px'}">
</el-table>
<div class="scroll_area" :style="{ height: scrollAreaHeight }"></div>
</div>
(2)在data中设置变量
showNum: 10,//显示几条数据
start: 0,//滚动过程显示的开始索引
end: 10,//滚动过程显示的结束索引
itemHeight: 30,
list: [],
scrollTop: 0,
(3)在computed计算内容总高度及虚拟列表需要显示的数据
computed: {
//内容总高度
scrollAreaHeight() {
return this.sonTableData.length * this.itemHeight + 'px';
},
//区可视的数据,
showList() {
return this.sonTableData.slice(this.start, this.end);
}
},
(4)在methods中需要使用的方法
//计算滚动
computescrollArea(scrollTop) {
scrollTop = scrollTop || 0;
this.showNum = Math.ceil(this.$refs.listView.clientHeight / this.itemHeight); // 取得可见区域的可见列表项数量
//开始的数组索引 滚到第几条数据 = 滚动高度 / 每个item的高度
this.start = Math.floor(scrollTop / this.itemHeight);
//结束索引 可视的数据 = 滚到第几条数据 + 显示几条数据
this.end = this.start + this.showNum;
//绝对定位对相对定位的偏移量 已滚动的高度 = 滚到第几条数据 * 每个item的高度
this.$refs.content.style.webkitTransform = `translate3d(0, ${this.start * this.itemHeight}px, 0)`;
// this.$refs.content.style.webkitTransform = `translateY(${start * this.itemHeight}px)`;
},
//滚动触发
handleScroll() {
//获取已滚动的高度
console.log("this.$refs.listView.scrollTop--",this.$refs.listView.scrollTop)
// const scrollTop = this.$refs.listView.scrollTop;
// this.computescrollArea(scrollTop);
this.scrollTop = this.$refs.listView.scrollTop;
this.computescrollArea(this.scrollTop);
},