结合康熙选秀讲解vue虚拟列表实现

 更新时间:2022年07月01日 17:11:22   作者:Sunshine_Lin  
这篇文章主要为大家介绍了结合康熙选秀讲解vue虚拟列表的原理使用,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪

场景

康熙选妃

话说这年是康熙五十三年,天下太平,天下无人不感叹这“康熙盛世”啊,康熙自己也是开心的不得了啊,“朕奋斗了大半辈子,还不能享乐享乐,传命张廷玉来见我,我有事要让他办!”

  • 康熙:衡臣啊(衡臣是张廷玉的字),这康熙盛世如何
  • 张廷玉:皇上牛逼,皇上牛逼,皇上万岁
  • 康熙:但是朕老了啊,但是朕不能服老,朕要证明给天下人看
  • 张廷玉:皇上正值壮年,万岁万万岁
  • 康熙:我不管,我要选妃,我要选妃,我要选妃!!!
  • 张廷玉:我tm。。。你tm都60了还选?你扛得住吗?大哥!
  • 康熙: 我不管,你给我去找,找一万个妙龄女子进宫,我要选妃
  • 张廷玉:选个毛,你顶不动的- 康熙:我不管,我有鹿血,鹿血一杯,法力无边
  • 张廷玉:不,你不行。
  • 康熙:你去不去?
  • 张廷玉:不去
  • 康熙: 你去不去
  • 张廷玉:我不去
  • 康熙:还想不想配享太庙了?
  • 张廷玉:皇上万岁,臣一定上的圣托

一个月后,一万名妙龄女子进宫了。但是难题又来了。这么多女子,不可能一次性让康熙选吧,那不得花了他的眼睛。

张廷玉灵机一动:可以让女子们分批进大殿让皇上选嘛。具体可以这么做:

  • 在皇上选妃的大殿外,再设置两个偏殿
  • 宫女们分批次进大殿让皇上看
  • 被看过的宫女们进左偏殿等待选妃结果,还没排到的宫女在右偏殿等待

这样既提高了选秀效率,又可以让皇上更轻松些。这样做的好处就是:

  • 皇上不需要一次性看一万个宫女,不用那么劳累
  • 皇上如果选到一半累了,也可以休息,隔天再选,反正选到第几批了,这些都已经记录下了
  • 皇上如果某一天回想起哪个宫女还不错,也可以往回查

多数据渲染

现在解决多数据渲染,相信大家可能会想到分页,触底加载,懒加载等等,但其实虚拟列表也是多数据高性能加载的一个重要解决方案。

虚拟列表的概念

虚拟滚动,就是根据容器可视区域的列表容积数量,监听用户滑动或滚动事件,动态截取长列表数据中的部分数据渲染到页面上,动态使用空白站位填充容器上下滚动区域内容,模拟实现原生滚动效果

  • 浏览器渲染===康熙选秀:一次性渲染10000个肯定会使浏览器压力大,造成用户体验差
  • 容器可视区域===选秀大殿:10000个排队去渲染,比如一次渲染10个
  • 上方下方区域===左右偏殿:轮不到你渲染,你就乖乖进空白区待着

实现

基本实现

  • 可视区域的高度
  • 列表项的高度
  • 可视区域能展示的列表项个数 = ~~(可视区域高度 / 列表项高度) + 2
  • 开始索引
  • 结束索引
  • 预加载(防止滚动过快,造成暂时白屏)
  • 根据开始索引和结束索引,截取数据展示在可视区域
  • 滚动节流
  • 上下空白区使用padding实现
  • 滑动到底,再次请求数据并拼接
<template>
  <div class="v-scroll" @scroll.passive="doScroll" ref="scrollBox">
    <div :style="blankStyle" style="height: 100%">
      <div v-for="item in tempSanxins" :key="item.id" class="scroll-item">
        <span>{{ item.msg }}</span>
        <img :src="item.src" />
      </div>
    </div>
  </div>
</template>
<script>
import { throttle } from "../../utils/tools";
export default {
  data() {
    return {
      allSanxins: [], // 所有数据
      itemHiehgt: 150, // 列表每一项的宽度
      boxHeight: 0, // 可视区域的高度
      startIndex: 0, // 元素开始索引
    };
  },
  created() {
    // 模拟请求数据
    this.getAllSanxin(30);
  },
  mounted() {
    // 在mounted时获取可视区域的高度
    this.getScrollBoxHeight();
    // 监听屏幕变化以及旋转,都要重新获取可视区域的高度
    window.onresize = this.getScrollBoxHeight;
    window.onorientationchange = this.getScrollBoxHeight;
  },
  methods: {
    getAllSanxin(count) {
      // 模拟获取数据
      const length = this.allSanxins.length;
      for (let i = 0; i < count; i++) {
        this.allSanxins.push({
          id: `sanxin${length + i}`,
          msg: `我是三心${length + i}号`,
          // 这里随便选一张图片就行
          src: require("../../src/asset/images/sanxin.jpg").default,
        });
      }
    },
    // 使用节流,提高性能
    doScroll: throttle(function () {
      // 监听可视区域的滚动事件
      // 公式:~~(滚动的距离 / 列表项 ),就能算出已经滚过了多少个列表项,也就能知道现在的startIndex是多少
      // 例如我滚动条滚过了160px,那么index就是1,因为此时第一个列表项已经被滚上去了,可视区域里的第一项的索引是1
      const index = ~~(this.$refs.scrollBox.scrollTop / this.itemHiehgt);
      if (index === this.startIndex) return;
      this.startIndex = index;
      if (this.startIndex + this.itemNum > this.allSanxins.length - 1) {
        this.getAllSanxin(30);
      }
    }, 200),
    getScrollBoxHeight() {
      // 获取可视区域的高度
      this.boxHeight = this.$refs.scrollBox.clientHeight;
    },
  },
  computed: {
    itemNum() {
      // 可视区域可展示多少个列表项? 计算公式:~~(可视化区域高度 / 列表项高度) + 2
      // ~~是向下取整的运算符,等同于Math.floor(),为什么要 +2 ,是因为可能最上面和最下面的元素都只展示一部分
      return ~~(this.boxHeight / this.itemHiehgt) + 2;
    },
    endIndex() {
      // endIndex的计算公式:(开始索引 + 可视区域可展示多少个列表项 * 2)
      // 比如可视区域可展示8个列表项,startIndex是0的话endIndex就是0 + 8 * 2 = 16,startIndex是1的话endIndex就是1 + 8 * 2 = 17,以此类推
      // 为什么要乘2呢,因为这样的话可以预加载出一页的数据,防止滚动过快,出现暂时白屏现象
      let index = this.startIndex + this.itemNum * 2;
      if (!this.allSanxins[index]) {
         // 到底的情况,比如startIndex是99995,那么endIndex本应该是99995 + 8 * 2 = 10011
        // 但是列表数据总数只有10000条,此时就需要让endIndex = (列表数据长度 - 1)
        index = this.allSanxins.length - 1;
      }
      return index;
    },
    tempSanxins() {
      //   可视区域展示的截取数据,使用了数组的slice方法,不改变原数组又能截取
      let startIndex = 0;
      if (this.startIndex <= this.itemNum) {
        startIndex = 0;
      } else {
        startIndex = this.startIndex + this.itemNum;
      }
      return this.allSanxins.slice(startIndex, this.endIndex + 1);
    },
    blankStyle() {
      // 上下方的空白处使用padding来充当
      let startIndex = 0;
      if (this.startIndex <= this.itemNum) {
        startIndex = 0;
      } else {
        startIndex = this.startIndex - this.itemNum;
      }
      return {
        // 上方空白的高度计算公式:(开始index * 列表项高度)
        // 比如你滚过了3个列表项,那么上方空白区高度就是3 * 150 = 450,这样才能假装10000个数据的滚动状态
        paddingTop: startIndex * this.itemHiehgt + "px",
         // 下方空白的高度计算公式:(总数据的个数 - 结束index - 1) * 列表项高度
        // 例如现在结束index是100,那么下方空白高度就是:(10000 - 100 - 1) * 150 = 1,484,850
        paddingBottom:
          (this.allSanxins.length - this.endIndex - 1) * this.itemHiehgt + "px",
          // 不要忘了加px哦
      };
    },
  },
};
</script>
<style lang="scss" scoped>
.v-scroll {
  height: 100%;
  /* padding-bottom: 500px; */
  overflow: auto;
  .scroll-item {
    height: 148px;
    /* width: 100%; */
    border: 1px solid black;
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0 20px;
    img {
      height: 100%;
    }
  }
}
</style>

以上就是结合康熙选秀讲解vue虚拟列表的详细内容,更多关于vue虚拟列表的资料请关注脚本之家其它相关文章!

相关文章

  • vue实现的仿淘宝购物车功能详解

    vue实现的仿淘宝购物车功能详解

    这篇文章主要介绍了vue实现的仿淘宝购物车功能,结合完整实例形式较为详细的分析了vue.js仿淘宝购物车功能的具体样式、功能相关实现技巧与操作注意事项,需要的朋友可以参考下
    2019-01-01
  • Vue封装组件并上传到npm的教程详解

    Vue封装组件并上传到npm的教程详解

    这篇文章主要为大家详细介绍了Vue封装组件并上传到npm的相关教程,文中的示例代码讲解详细,具有一定的借鉴价值,有需要的小伙伴可以参考下
    2024-04-04
  • vue3中使用ref和emit来减少props的使用示例详解

    vue3中使用ref和emit来减少props的使用示例详解

    现在在开发vue3项目的过程中,我们开发小组渐渐的减少props的使用,转而用ref 和 emit 来代替,这篇文章主要介绍了vue3中使用ref和emit来减少props的使用,需要的朋友可以参考下
    2022-06-06
  • Vue router的addRoute方法实现控制权限方法详解

    Vue router的addRoute方法实现控制权限方法详解

    这篇文章主要介绍了vue动态路由添加,vue-router的addRoute方法实现权限控制流程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习吧
    2022-09-09
  • 基于Vue3和Element Plus实现可扩展的表格组件

    基于Vue3和Element Plus实现可扩展的表格组件

    在开发过程中,我们经常需要创建具有复杂功能的表格组件,本文将介绍如何使用 Vue 3 和 Element Plus 库来构建一个可扩展的表格组件,文中有详细的代码示例供大家参考,需要的朋友可以参考下
    2024-07-07
  • vue 设置proxyTable参数进行代理跨域

    vue 设置proxyTable参数进行代理跨域

    这篇文章主要介绍了vue 设置proxyTable参数进行代理跨域的相关资料,及代理跨域的概念原理,需要的朋友可以参考下
    2018-04-04
  • vue中为何方法要写在methods的里面

    vue中为何方法要写在methods的里面

    这篇文章主要介绍了vue中为何方法要写在methods的里面,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-10-10
  • vue打包时不删除dist里的原有文件配置方法

    vue打包时不删除dist里的原有文件配置方法

    这篇文章主要为大家介绍了vue打包时不删除dist里的原有文件配置方法详解,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2023-11-11
  • vue三元运算之多重条件判断方式(多个枚举值转译)

    vue三元运算之多重条件判断方式(多个枚举值转译)

    这篇文章主要介绍了vue三元运算之多重条件判断方式(多个枚举值转译),具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-09-09
  • vue图片懒加载的两种方法详解

    vue图片懒加载的两种方法详解

    懒加载是一种网页优化技术,也被称为延迟加载,它的主要目的是在网页加载时,只加载当前可见区域内的内容,而延迟加载其他不可见区域的内容,从而提高网页的加载速度和性能,这篇文章主要介绍了vue图片懒加载的两种方法,需要的朋友可以参考下
    2023-07-07

最新评论