前端高性能渲染 — 虚拟列表

虚拟列表,实际上就是在首屏加载的时候,只加载可视区域内需要的列表项,当滚动发生时,动态通过计算获得可视区域内的列表项,并将非可视区域内存在的列表项删除。该技术是解决渲染大量数据的一种解决方法。
实现虚拟列表,需要获取以下几个属性

  1. 可视区域起始数据索引(startIndex)
  2. 可视区域结束数据索引(endIndex)
  3. 计算可视区域数据,并渲染到页面中
  4. 计算startIndex对应的数据在整个列表中的偏移位置listTop并设置到列表上

高度固定

令App组件(父组件)产生一万条虚拟数据来模拟接口,在List组件中实现对应的功能

App组件:

<template>
  <div>
    <List :items="items" :size="60" :shownumber="10"></List>
  </div>
</template>

<script>
import List from '@/List.vue'
export default {
  components: {
    List
  },
  computed: {
    // 模拟数据
    items() {
      return Array(10000).fill('').map((item, index) => ({
        id: index,
        content: index
      }))
    }
  }
};
</script>

<style scoped></style>

List组件:

<template>
    <div class="container" :style="{ height: containerHeight }" @scroll="handleScroll" ref="container">
        <!-- 数据列表 -->
        <div class="list" :style="{top:listTop}">
            <!-- 列表项 -->
            <div v-for="item in showData" :key="item.id" :style="{height:size+'px'}">
                {{ item.content }}
            </div>
            <!-- 用于撑开高度的元素 -->
            <div class="bar" :style="{height:barHeight}"></div>
        </div>
    </div>
</template>

<script>
export default {
    name: 'List',
    props:{
        // 要渲染的数据
        items:{
            type:Array,
            required:true
        },
        // 每条数据渲染节点的高度
        size:{
            type:Number,
            required:true
        },
        // 每次渲染DOM节点个数
        shownumber:{
            type:Number,
            required:true
        }
    },
    data(){
        return{
            start:0,  //要展示数据的其实下标
            end:this.shownumber  //结束下标
        }
    },
    computed:{
        // 最终展示数据
        showData(){
            return this.items.slice(this.start,this.end)
        },
        // 容器的高度
        containerHeight(){
            return this.size * this.shownumber + 'px'
        },
        // 撑开容器内部高度的元素的高度
        barHeight(){
            return this.size * this.items.length + 'px'
        },
        // 列表项上滚动改变top的值
        listTop(){
            return this.start * this.size + 'px'
        },
    },
    methods:{
        // 容器滚动事件
        handleScroll(){
            // 获取容器顶部滚动的尺寸
            const scrollTop = this.$refs.container.scrollTop
            this.start = Math.floor(scrollTop / this.size)
            this.end = this.start + this.shownumber
        }
    }
};
</script>

<style scoped>
.container{
    overflow-y: scroll;
    background-color: rgb(150,150,150,.5);
    font-size: 20px;
    font-weight: bold;
    line-height: 60px;
    width: 500px;
    margin: 0 auto;
    position: relative;
    text-align: center;
}
.list{
    position: absolute;
    top: 0;
    width: 100%;
}
</style>

这样可以实现一个简单的固定高度的虚拟列表功能。

你可能感兴趣的:(前端)