封装一个vue2的虚拟列表

当我们需要很多条数据时,比如一万条时,如果只用v-for的话那么会渲染出一万个dom元素,这样是很消耗性能的,这时我们便可以使用虚拟列表了。


那什么是虚拟列表呢?
顾名思义,就是一个虚假的列表,可能它里面只渲染了20个dom元素,但是却可以通过滚动来展示一万条数据。
这里我封装了一个简单的虚拟列表的组件,里面包含了 rowHeight:行高、viewCount:显示条数、listItem:每一行显示的内容、listData:需要渲染的整体数据,另外还添加了一个点击向父组件传递信息的方法 onClick


组件如下,可直接复制

<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>

使用方法如下:
在页面中引入这个组件

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

效果

虚拟列表效果

这样封装是比较便捷,但如果有大牛看到有需要修改的地方也欢迎留言呀

你可能感兴趣的:(javascript,前端,vue.js)