前言
本系列主要整理前端项目中需要掌握的知识点。本节介绍Vue2中如何使用虚拟列表。
一、使用场景
在项目中,有些请求可能一次性返回上千条信息,这是如果使用v-for循环创建dom节点,创建上千条节点将消耗大量的性能,且不利于首屏加载。
二、虚拟列表
以上的问题可以用虚拟列表来解决。虚拟列表的基本思路是,**在展示区只展示n个dom元素,而dom中展示哪部分内容则根据滚动条计算出来。**这样即使后端返回的数据再多,前端加载的dom元素也只有n个,利于首屏加载的同时也不会造成性能浪费。如图所示:
在图中,无论列表项内容到了多少项,DOM节点都只有10个,只不过是在不断更新而已。
三、虚拟列表的手写实现
-
思路与代码来自:凉爽爽爽爽爽爽爽爽爽的vue2 与 vue3 虚拟列表实现。
-
首先定义一个组件,用于虚拟列表的展示。传入的参数包括items(展示信息数组)、size(每条信息所占高度)、shownumber(每个可视区域展示的信息条数)
<List :items="items" :size="60" :shownumber="10"/>
-
组件内部的盒子组成如下:外层是一个container、展示列表的盒子是list、list中用v-for遍历展示数据的数组showData,其中showData.length=shownumber。如下图所示:
-
并给container绑定滚动事件,当滚动事件发生后,计算滚动距离,用滚动距离除以每条数据的高度,即可得到被滚动条卷入的数据条数,因此showData数组的起始位置应该是this.start = Math.floor(scrollTop/this.size),终止位置为起始位置加上数组长度this.end = this.start+this.shownumber。
computed: { // 最终筛选出的要展示的数据 showData () { return this.items.slice(this.start, this.end) }, } methods: { // 容器的滚动事件 handleScroll () { // 获取容器顶部滚动的尺寸 const scrollTop = this.$refs.container.scrollTop // 计算卷去的数据条数,用计算的结果作为获取数据的起始和结束下标 // 起始的下标就是卷去的数据条数,向下取整 this.start = Math.floor(scrollTop / this.size) // 结束的下标就是起始的下标加上要展示的数据条数 this.end = this.start + this.shownumber } }
-
还需要对list盒子进行定位,否则滚动条滚动后,dom数据虽然发生了变化,但是同时list盒子中需要展示的前几条数据也被滚动条圈进去了,如上图虚线中。所以就需要将container设置为相对定位,list设置为绝对定位,每次start值变了,便重新计算top的值。
<div class="list" :style="{ top: listTop }" > <script> export default { computed: { // 列表向上滚动时要动态改变 top 值 listTop () { return this.start * this.size + 'px' } } } </script>
-
完整代码如下:
App.vue中<!-- App.vue --> <template> <div id="app"> <List :items="items" :size="60" :shownumber="10" /> </div> </template> <script> import List from './components/List.vue' export default { name: 'App', components: { List, }, computed: { // 要进行渲染的数据列表