vue2虚拟列表

当数据很多时,比如一万条时,如果只用v-for的话那么会渲染出一万个dom元素,这样是很消耗性能的,这时我们便可以使用虚拟列表了。
那什么是虚拟列表呢?
顾名思义,就是一个虚假的列表,可能它里面只渲染了20个dom元素,但是却可以通过滚动来展示一万条数据。
这里封装了一个简单的虚拟列表的组件,里面包含了 rowHeight:行高、viewCount:显示条数、listItem:每一行显示的内容、listData:需要渲染的整体数据,另外还添加了一个点击向父组件传递信息的方法 onClick,实现效果如下:
在这里插入图片描述

具体实现方法:
1.写个组件,如下:

<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.在需要使用的页面引入组件

<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,"<=========");
        }
    },
};

猜你喜欢

转载自blog.csdn.net/Hyanl/article/details/129303582