When there is a lot of data, such as 10,000 items, if only v-for is used, then 10,000 dom elements will be rendered, which consumes a lot of performance. At this time, we can use a virtual list.
So what is a virtual list?
As the name suggests, it is a false list, which may only render 20 dom elements, but it can display 10,000 pieces of data by scrolling.
A simple virtual list component is encapsulated here, which includes rowHeight: row height, viewCount: number of displayed items, listItem: content displayed in each row, listData: overall data that needs to be rendered, and a click is added to the parent component The method of onClick to transmit information, the effect is as follows:
The specific implementation method:
1. Write a component, as follows:
<template>
<div class="viewPort" ref="viewPort" :style="{'--scroll-eight':rowHeight+'px'}" @scroll="handleScroll">
<div class="scrollBar" ref="scrollBar"></div>
<div class="list" ref="list">
<div class="row" ref="row" v-for="(item,index) in finalList" :key="index" @click="handleClick(item)">
{
{
listItem?item[listItem]:item }}
</div>
</div>
</div>
</template>
<script>
export default {
data() {
return {
startIndex:0, // 开始索引默认为0
endIndex:this.viewCount, // 结束索引为列表展示条数
};
},
props:{
// 行高
rowHeight:{
type:Number,
default:20,
},
// 显示条数
viewCount:{
type:Number,
default:20,
},
// 显示内容
listItem:{
type:String,
required:true
},
// 数据
listData:{
type:Array,
required:true
}
},
computed:{
finalList(){
return this.listData.slice(this.startIndex,this.endIndex); // 展示的数据
}
},
mounted() {
this.$refs.viewPort.style.height = this.$refs.list.style.height = this.rowHeight*this.viewCount + "px"; // 视口高度动态赋值
this.$refs.scrollBar.style.height = (this.listData.length * this.rowHeight) + "px"; // 滚动条高度动态赋值
},
methods: {
handleScroll(){
this.startIndex = Math.round(this.$refs.viewPort.scrollTop/this.rowHeight); // 开始索引
this.endIndex = this.startIndex + this.viewCount; // 结束索引
this.$refs.list.style.transform = `translateY(${
this.startIndex*this.rowHeight}px)`; // 向下平移
},
handleClick(e){
this.$emit("onClick",e); // 绑定onClick事件,向调用者传递数据
}
},
};
</script>
<style scoped lang="scss">
.viewPort{
width: 100%;
overflow-y: auto;
position: relative;
background-color: #ff0;
.list{
position: absolute;
top: 0;
left: 0;
width: 100%;
.row{
height: var(--scroll-eight);
width: 100%;
&:hover{
background-color: #eee;
color: #f0f;
}
&:active{
background-color: #eee;
color: #f0f;
}
}
}
}
</style>
2. Introduce components in the pages that need to be used
<template>
<div>
<v-list :list-item="title" :list-data="listData" @onClick="onClick" :view-count="10" :row-height="15"></v-list>
</div>
</template>
<script>
import VList from './vList.vue'
export default {
components:{
VList},
data() {
let arrList = new Array(10000).fill(null).map((item,index)=>{
return {
title: index+1}});
return {
listData:'title',
listData:Object.freeze(arrList)
};
},
methods: {
onClick(e){
console.log(e,"<=========");
}
},
};