标题:Vue长列表优化之虚拟列表实现过程详解
1. 前言
在处理Vue中长列表(包含大量子组件)时,当数据更新时,会造成较大的性能问题。因此,为了提高Vue应用的性能,我们通常会做一些长列表的优化。其中,虚拟列表技术是一种高效的长列表优化方法。本文旨在介绍Vue中如何利用虚拟列表技术实现长列表优化。
2. 虚拟列表实现过程详解
2.1 什么是虚拟列表
虚拟列表是指只渲染当前滚动区域内的子组件,而不是全部渲染。当用户滚动列表时,只有当前可见区域内的列表项才会被渲染,同时被滚动到可见区域外的列表项则会被销毁。这种做法不仅能够提高列表的渲染性能,同时也能够节省内存空间。
2.2 实现过程
2.2.1 计算总高度
虚拟列表的实现需要先计算出列表项总高度,以便后续做一些计算处理。
mounted() {
// 计算每个列表项高度
this.itemHeight = this.$refs.item[0].clientHeight
// 计算列表总高度
this.totalHeight = this.itemHeight * this.list.length
}
2.2.2 计算显示区域
然后我们需要计算出当前屏幕可见区域内的列表项。我们可以通过计算可视区域内第一项的索引来实现。
watch: {
scrollTop(newVal) {
this.start = Math.floor(newVal / this.itemHeight)
// 为了避免底部区域不足一个完整的列表项高度而导致渲染的列表项不完整,需向下取整
this.end = Math.ceil((newVal + this.visibleHeight) / this.itemHeight)
}
}
2.2.3 渲染虚拟列表
接下来是实现虚拟列表的关键步骤,即在计算出显示区域后,只渲染这些显示区域内的列表项。为了实现这个目的,我们需要在模板中加入一个用来展示虚拟列表项的容器,然后根据计算出的start和end索引,只渲染这些需要展示的列表项。
<template>
<div class="list-container" ref="listContainer" @scroll="onScroll">
<div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
<div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
{{item}}
</div>
</div>
</div>
</template>
关键部分是"v-show"指令,根据计算出的"start"和"end"索引,只渲染当前显示区域内的列表项。
3. 示例说明
3.1 示例1
实现一个包含10000个列表项的虚拟列表组件。其中,每个列表项是一个文本框,用户可以在里面输入内容。在用户在文本框中输入内容时,控制台将输出当前列表项的内容。
<template>
<div class="list-container" ref="listContainer" @scroll="onScroll">
<div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
<div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
<input type="text" placeholder="请输入内容" v-model="item" @input="onInput(index)">
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
itemHeight: 40,
visibleHeight: 500 // 可视区域高度
}
},
mounted() {
this.initList()
},
methods: {
initList() {
// 初始化列表数据
for (let i = 0; i < 10000; i++) {
this.list.push('item' + i)
}
// 计算每个列表项高度
this.itemHeight = this.$refs.item[0].clientHeight
// 计算列表总高度
this.totalHeight = this.itemHeight * this.list.length
},
onScroll() {
// 计算当前可见区域的索引
this.start = Math.floor(this.$refs.listContainer.scrollTop / this.itemHeight)
this.end = Math.ceil((this.$refs.listContainer.scrollTop + this.visibleHeight) / this.itemHeight)
},
onInput(index) {
// 输出列表项内容
console.log(this.list[index])
}
}
}
</script>
此示例中,列表项使用input标签来展示,用户在输入内容时,控制台将输出当前列表项的内容。
3.2 示例2
实现一个包含100个图片的虚拟列表组件。其中,每个列表项是一个图片容器。当用户滚动列表时,用随机生成的颜色来填充图片,并展示在列表项中。
<template>
<div class="list-container" ref="listContainer" @scroll="onScroll">
<div class="virtual-list" :style="{height: totalHeight + 'px', paddingTop: start * itemHeight + 'px', paddingBottom: (list.length - end) * itemHeight + 'px'}">
<div class="item" v-for="(item, index) in list" :key="index" :ref="'item-' + index" :style="{top: index * itemHeight + 'px'}" v-show="index >= start && index < end">
<div class="img-container">
<div class="img" :style="{backgroundColor: item.color}"></div>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
list: [],
itemHeight: 300,
visibleHeight: 500 // 可视区域高度
}
},
mounted() {
this.initList()
},
methods: {
initList() {
// 初始化列表数据
for (let i = 0; i < 100; i++) {
this.list.push({color: this.getRandomColor()})
}
// 计算每个列表项高度
this.itemHeight = this.$refs.item[0].clientHeight
// 计算列表总高度
this.totalHeight = this.itemHeight * this.list.length
},
onScroll() {
// 计算当前可见区域的索引
this.start = Math.floor(this.$refs.listContainer.scrollTop / this.itemHeight)
this.end = Math.ceil((this.$refs.listContainer.scrollTop + this.visibleHeight) / this.itemHeight)
// 更新列表项颜色,随机生成
for (let i = this.start; i < this.end; i++) {
this.$set(this.list[i], 'color', this.getRandomColor())
}
},
getRandomColor() {
// 生成随机颜色
return '#' + Math.floor(Math.random() * 16777215).toString(16)
}
}
}
</script>
此示例中,列表项为图片容器,当用户滚动列表时,随机生成一个颜色来渲染图片,并展示在列表项中。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:vue长列表优化之虚拟列表实现过程详解 - Python技术站