为什么要使用virtual list

当有大量数据生成DOM并渲染时,界面会非常耗时且卡顿。通常会使用virtual list来解决问题,virtual list原理是只渲染可见区域,非可见区域不渲染。

不使用virtual list

  1. 一次性渲染全部

在这里插入图片描述

<template>
    <div ref="box" class="vl-box" :style="{ height: height + 'px' }">
        <div :style="{ height: boxHeight + 'px' }">
            <div
                class="vl-box-item"
                :style="{
                    height: rowHeight + 'px',
                    lineHeight: rowHeight + 'px'
                }"
                v-for="item in data"
                :key="item.index"
            >{{ item }}</div>
        </div>
    </div>
</template>

<script>
export default {

    data() {
        return {
            data: Array(100).fill('').map((v, i) => { return { index: i } }),
            height: 200,
            rowHeight: 30,
        }
    },
}
</script>

<style scoped>
.vl-box {
    border: 2px solid #0094ff;
    overflow: auto;
}

.vl-box-item {
    box-sizing: border-box;
    border-bottom: 1px dotted red;
}
</style>>

使用virtual list

  1. 固定virtual list高度
  2. 固定virtual list每一行高度,计算偏移量

在这里插入图片描述

<template>
    <div ref="box" class="vl-box" :style="{ height: height + 'px' }">
        <div :style="{ height: boxHeight + 'px' }">
            <div
                class="vl-box-item"
                :style="{
                    height: rowHeight + 'px',
                    lineHeight: rowHeight + 'px',
                    top: (index + offsetIndex) * rowHeight + 'px'
                }"
                v-for="(item,index) in offsetData"
                :key="item.index"
            >{{ item }}</div>
        </div>
    </div>
</template>

<script>
export default {

    data() {
        return {
            data: Array(100).fill('').map((v, i) => { return { index: i } }),
            height: 200,
            rowHeight: 30,
            offset: 0,
            offsetIndex: 0
        }
    },
    computed: {
        boxHeight() {
            return this.data.length * this.rowHeight;
        },
        offsetData() {
            let count = Math.ceil(this.height / this.rowHeight);
            let index = Math.floor(this.offset / this.rowHeight);
            this.offsetIndex = index;
            return this.data.slice(index, count + index);
        }
    },
    mounted() {
        this.$refs.box.addEventListener('scroll', () => {
            this.offset = this.$refs.box.scrollTop;   
            console.log(this.offset )       
        },false)
    },
}
</script>

<style scoped>
.vl-box {
    border: 2px solid #0094ff;
    overflow: auto;
}
.vl-box > div {
    overflow: hidden;
    position: relative;
}
.vl-box > div > div {
    position: absolute;
    width: 100%;
}
.vl-box-item {
    box-sizing: border-box;
    border-bottom: 1px dotted red;
}
</style>>

Logo

前往低代码交流专区

更多推荐