大量数据渲染存在性能问题,解决方法之一(虚拟滚动)

  • 滚动定位三种(transform偏移、padding-top填充、absolute定位)
  • 示例paddingTop填充方法,剩余两种方法实现方式与其大致相同
<template>
    <div class="t-container">
        <div class="wrapper" ref="wrapper" @scroll="handleScroll">
            <div class="wrapper-scroll" :style="{height:`${wrapperScrollH}px`, paddingTop:`${paddingTop}px`}">
                <div v-for="item in showList" :key="item.index">
                    <span class="title">{{item.index}} 测试</span>
                    <ul>
                        <li class="test">就问你<span>大量数据<span>x</span></span></li>
                        <li class="test">卡不卡<span>虚拟滚动<span>z</span></span></li>
                        <li class="test">不知道<span>小案例<span>p</span></span></li>
                        <li class="test">真的吗<span>页面测试<span>就是玩</span></span></li>
                        <li class="test">{{item.content}}<span></span></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
</template>
<script>
import { reactive, ref, computed } from "@vue/composition-api"
export default {
    setup(props, context){
        // 子元素高度设置为150
        let arr = reactive([]);
        const wrapper = ref(null);
        let start = ref(0);
        let end = ref(10);
        // 滚动条滚动回调
        const handleScroll = (e)=>{
        	// 滚动条到容器顶部距离
            let top = e.srcElement.scrollTop;
            // 计算数据开始渲染下标,
            let iTop = parseInt(top / 150);
            // start 需要iTop - 5, 使页面更为流畅,往前多渲染5条数据
            start.value = iTop > 5 ? iTop - 5 : 0;
            // 未渲染数据,使用padding占位
            paddingTop.value = start.value * 150;
            // 计算数据结束渲染下标
            let iwTop = parseInt((top + wrapperH) / 150);
            // 往后多渲染5条数据,页面更为流畅
            end.value = iwTop + 5;
        };
        // 渲染10万条数据
        const total = 100000;
        for(let i = 0; i < total; i++){
            arr.push({
                index:i,
                content: i + "测试效果" + Math.random()
            });
        }
        // 计算需要渲染真实dom的数据
        const showList = computed(()=>{
            return [...arr.slice(start.value, end.value)]
        });
        let wrapperH = ref(0);
        let wrapperScrollH = ref(0);
        // 获取容器高度,与设置滚动区域高度
        onMounted(()=>{
            wrapperScrollH.value = arr.length * 150;
            wrapperH = wrapper.value.clientHeight;
        });
        let paddingTop = ref(0);
        return {
            arr,
            wrapper,
            handleScroll,
            showList,
            wrapperScrollH,
            wrapperH,
            paddingTop
        }
    }
}
</script>
<style scoped lang="stylus">
.t-container
    padding 20px
    background-color pink
    width 800px
    height 400px
    margin 10px auto
    >div
        margin 10px auto
    .wrapper
        height calc(100% - 40px)
        overflow auto 
        .wrapper-scroll
            display flex
            flex-direction column
            overflow hidden
        .title, .test
            line-height 20px
        li
            list-style none
            margin 5px 40px
</style>
Logo

技术共进,成长同行——讯飞AI开发者社区

更多推荐