温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

vue虚拟滚动性能优化的方法

发布时间:2022-08-10 10:55:36 来源:亿速云 阅读:195 作者:iii 栏目:开发技术

本文小编为大家详细介绍“vue虚拟滚动性能优化的方法”,内容详细,步骤清晰,细节处理妥当,希望这篇“vue虚拟滚动性能优化的方法”文章能帮助大家解决疑惑,下面跟着小编的思路慢慢深入,一起来学习新知识吧。

    引言

    一个简单的情景模拟(千万别被带入):

    A: 假设现在有 10 万条数据,你作为前端该怎么优化这种大数据的列表?

    B: 针对大数据列表一般不会依次性加载,会采用上拉加载、分页加载等方式实现优化.

    A: 那假如加载到最后一条数据的时候,页面上只是列表部分的数据就至少对应 10 万个 dom 节点,你觉得一个页面渲染至少 10 万个 dom 节点的性能如何?

    A: 如果这样的列表有 n 个呢?还有没有别的优化方式?

    B: 要不我把自己优化一下 ......

    其实解决上述问题就可以使用 虚拟滚动 来实现优化,相信大家对这个词都不陌生,但由于这个名词比较短(又是虚拟,又是滚动)导致很多人觉得这是非常高大上、难以理解的内容,但其实恰恰相反。

    本文的目的就是帮助你以 最简单 的方式 理解虚拟滚动,甚至实现 虚拟滚动.

    虚拟滚动(Virtual Scrolling)

    理解虚拟滚动

    其实要理解 虚拟滚动 这个词很简单,按照 虚拟 和 滚动 两部分来理解就很简单了,下面就一一拆解。

    虚拟

    通常在页面列表中,要渲染的 列表数量 和真实在文档中存在的 DOM 节点数 是 1 : 1 的。

    每个列表项都拥有相同的高度(假设是 30px),这个列表容器中需要完全渲染的列表数(假设是 100 条)和在页面中的高度是一致的,即此时的高度就为 100 * 30 = 300 px,对应列表的 DOM 数量为 100,如:

    vue虚拟滚动性能优化的方法

    对于 虚拟滚动 来讲,虚拟 的意思是指实际要渲染完整列表对应的高度是通过 虚拟计算 的,并不是指文档中存在对应的 DOM 节点数。

    上面的栗子对应到虚拟滚动来讲,就意味着实际渲染完整列表对应的高度就仍为 100 * 30 = 300px,但实际渲染数就变为 10 条,关系图大致如下:

    vue虚拟滚动性能优化的方法

    滚动

    所谓 滚动 就很好理解了,因为列表可视区通常会限制一定的高度,即 列表可视区高度,那么此时只要 虚拟列表高度 值大于 列表可视区高度 时,就会产生滚动条即可发生滚动操作。

    值得注意的是,在发生滚动时需要对 实际渲染的列表 进行一些处理,否则会出现 实际渲染的列表 和 虚拟列表区 脱离的情况,比如:

    vue虚拟滚动性能优化的方法

    关键点就是实现在发生 滚动 操作时,保证 实际渲染的列表 一直存在 列表可视区 中,并且动态切换需要渲染的列表数据。

    实现虚拟滚动

    核心步骤
    • 设置列表可视区的高度 containerHeight

    • 设置单个列表项的高度 listItemHeight

    • 计算渲染完整列表需要的高度 virtualHeight,即 virtualHeight = listItemHeight * data.length

    • 设置真实渲染数据的起始索引 startIndex、endIndex,用于从列表数据 data 中获取对应的数据内容

    • 注册/监听滚动事件 onScroll

      • 获取当前实际滚动距离 eleScrollTop

      • 将 eleScrollTop 作为 translateY 的值,即 实际渲染列表元素 平移的数值,保证 实际渲染列表元素 一直存在可视区中

      • 根据实际的滚动距离 eleScrollTop,动态计算列表新的起始索引 startIndex、endIndex

    效果预览

    vue虚拟滚动性能优化的方法

    具体实现细节都在如下的代码中,可结合其中的注释阅读:

    // App.vue
    <script>
    const list = (num = 10)=> {
      const data = [];
      for (let i = 0; i < num; i++) {
        data.push({
          id: i+1,
          name: `第 ${i+1} 条列表`
        });
      }
      return data;
    }
    </script>
    <template>
      <VirtualScroll :data="list(100)" />
    </template>
    // VirtualScroll.vue
    <template>
      <!-- 虚拟滚动内容 -->
      <div
        class="virtual-scroller"
        @scroll="onScroll"
        :
      >
        <!-- 实际渲染的列表内容 -->
        <ul
          class="real-list-content"
          :
        >
          <li
            v-for="item in visibleList"
            :key="item.id"
            :style="{
              height: `${listItemHeight}px`,
              'line-height': `${listItemHeight}px`,
            }"
          >
            <div>{{ item.name }}</div>
          </li>
        </ul>
        <!-- 虚拟列表元素 -->
        <div class="virtual-height" :>
          ~ 数据加载完毕 ~
        </div>
      </div>
    </template>
    <script>
    export default {
      name: "vue-virtual-scroll",
    };
    </script>
    <script setup language="ts">
    import { computed, ref } from "vue";
    const props = defineProps({
      data: {
        type: Array,
        default: [],
      },
      startIndex: {
        type: Number,
        default: 0,
      },
      endIndex: {
        type: Number,
        default: 10,
      },
      listItemHeight: {
        type: Number,
        default: 60,
      },
      containerHeight: {
        type: Number,
        default: 500,
      },
    });
    let { data, listItemHeight } = props;
    const tranlateY = ref(0); // 平移距离
    const startIndex = ref(props.startIndex); // 开始索引
    const endIndex = ref(props.endIndex); // 结束索引
    // 实际渲染的数据
    const visibleList = computed(() => {
      return data.slice(startIndex.value, endIndex.value);
    });
    // 虚拟滚动的高度
    const virtualHeight = computed(() => {
      return (data.length - visibleList.value.length) * listItemHeight + listItemHeight;
    });
    // 滚动事件
    const onScroll = (e) => {
      const eleScrollTop = e.target.scrollTop;
      // 保证实际渲染列表一直停留在可视区
      tranlateY.value = eleScrollTop;
      // 根据实际的滚动距离,动态计算列表开始索引
      startIndex.value = Math.floor(eleScrollTop / listItemHeight);
      // 基于开始索引
      endIndex.value = startIndex.value + 10;
    };
    </script>
    <style scoped>
    .virtual-scroller {
      border: solid 1px #eee;
      margin-top: 10px;
      height: 600px;
      overflow: auto;
    }
    .virtual-height {
      background: red;
      display: flex;
      align-items: end;
      justify-content: center;
      color: #fff;
    }
    ul {
      list-style: none;
      padding: 0;
      margin: 0;
    }
    li {
      outline: solid 1px #fff;
      background-color: #000;
      color: #fff;
    }
    </style>

    读到这里,这篇“vue虚拟滚动性能优化的方法”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

    向AI问一下细节

    免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

    vue
    AI