结合康熙选秀讲解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虚拟列表的资料请关注我们其它相关文章!

(0)

相关推荐

  • 使用 Vue 实现一个虚拟列表的方法

    因为 DOM 性能瓶颈,大型列表存在难以克服的性能问题. 因此,就有了 "局部渲染" 的优化方案,这就是虚拟列表的核心思想. 虚拟列表的实现,需要重点关注的问题一有以下几点: 可视区域的计算方法 可视区域的 DOM 更新方案 事件的处理方案 下面逐一分解说明. 可视区域计算 可视区域的计算,就是使用当前视口的高度.当前滚动条滚过的距离,得到一个可视区域的坐标区间. 算出可视区域的坐标区间之后,在去过滤出落在该区间内的列表项,这个过程,列表项的坐标也是必须能算出的. 思考以下情况, 我们

  • Vue 虚拟列表的实战示例

    序言 现如今,我们总是在无止境的刷.刷微博.刷抖音.刷沸点......一次次丝滑下拉体验的背后却是前端攻城狮的用心. 本篇讨论基于 Vue.js 的列表无限下拉实践. 我们的目标就是:让列表下拉纵享丝滑,而不是像以往的下拉就 loading 等待的体验. 译自 Better Programming 在线 Demo 设计 咱还是用 Vue CLI 来快速构建项目. 这是主页面: // EndlessList.vue <template> <div class="endless-s

  • vxe-list vue 如何实现下拉框的虚拟列表

    目录 vxe-list vue 下拉框的虚拟列表 虚拟列表的实现原理 接下来测试一下 vue虚拟列表实现原理 应用场景 实现思路 基础实现 vxe-list vue 下拉框的虚拟列表 vxe-table vxe-list vue 实现下拉框的虚拟列表 虚拟列表的实现原理 只渲染可视区的 dom 节点,其余不可见的数据卷起来,只会渲染可视区域的 dom 节点,提高渲染性能及流畅性,优点是支持海量数据的渲染:当然也会有缺点:滚动效果相对略差(海量数据与滚动效果的取舍问题就看自己的需求喽): <div

  • vue实现虚拟列表功能的代码

    当数据量较大(此处设定为10w),而且要用列表的形式展现给用户,如果我们不做处理的话,在浏览器中渲染10w dom节点,是极其耗费时间的,那我的Macbook air举例,10w条数据渲染出来到能看到页面,需要13秒多(实际应该是10秒左右),如果是用户的话肯定是不会等一个网页十几秒的 我们可以用虚拟列表解决这个问题 一步步来 首先看一下效果 这是data中的数据 data() { return { list: [], // 贼大的数组 li: { // 列表项信息 height: 50, },

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

    目录 场景 康熙选妃 多数据渲染 虚拟列表的概念 实现 基本实现 场景 康熙选妃 话说这年是康熙五十三年,天下太平,天下无人不感叹这“康熙盛世”啊,康熙自己也是开心的不得了啊,“朕奋斗了大半辈子,还不能享乐享乐,传命张廷玉来见我,我有事要让他办!” 康熙:衡臣啊(衡臣是张廷玉的字),这康熙盛世如何 张廷玉:皇上牛逼,皇上牛逼,皇上万岁 康熙:但是朕老了啊,但是朕不能服老,朕要证明给天下人看 张廷玉:皇上正值壮年,万岁万万岁 康熙:我不管,我要选妃,我要选妃,我要选妃!!! 张廷玉:我tm...你

  • vue实现虚拟列表组件解决长列表性能问题

    目录 一.虚拟列表 二.实现思路 难点与思考: 其他注意事项: 三.实现 最终实现效果 实现代码 模拟数据的后端代码 四.封装为组件 props: event: 虚拟列表组件代码 使用代码 最近项目中需要用到列表的展示,且不分页.当数据加载太多时会造成性能问题.因此采用虚拟列表来优化 一.虚拟列表 真实列表:每条数据都展示到html上,数据越多,DOM元素也就越多,性能也就越差. 虚拟列表:只展示部分数据(可见区域展示数据),当屏幕滚动时替换展示的数据,DOM元素的数量是固定的,相比较真实列表更

  • vue长列表优化之虚拟列表实现过程详解

    目录 前言 实现原理 实现代码 总结 前言 应用场景:后台一次性发送上千条或更多数据给前台 场景模拟:用户发起一个请求,后台发送了10w条数据 使用虚拟列表之前:前台需要生成10w个dom节点用来渲染页面 使用虚拟列表之后:前台只需要生成少量dom节点(dom节点数量取决于前端视图需要展示的数量),就可以实现对这10w条数据的视图渲染 总之:虚拟列表就是固定dom节点数量,通过修改dom节点的内容而达到不重新增加(或删除)dom节点来实现列表的更新 实现原理 监听页面滚动,获取滚动的高度scro

  • vue虚拟化列表封装的实现

    目录 vue虚拟化列表封装 将下面代码复制一份到自己的项目中 vue虚拟列表-vue-virtual-scroll-list 使用场景 安装 使用 vue虚拟化列表封装 将下面代码复制一份到自己的项目中 <template> <div class="scrollParent" ref="scrollContent" @scroll="handleScroll"> <div :style="blankFill

  • 基于vue循环列表时点击跳转页面的方法

    1.在data数组里边添加id(说明:我的是虚拟数据) 2.在点击事件上传入id参数,如下: 3.在methods里边添加点击跳转的方法,不要忘记在function后边的括号内传入id,然后判断如果id==1,就跳转那个页面,id==2跳转那个页面. 至此跳转完成. 附加: 点击返回上一页方法: window.history.go(-1);就是返回上一页.(不要忘记在标签上添加click点击事件) returnS:function () { window.history.go(-1); } 以上

  • 关于vue的列表图片选中打钩操作

    首先 css,美化checkbox样式,这一段代码拿过去可以直接用 label { font-size: 25px; cursor: pointer; position: absolute; top: -10px; right: 0px; z-index: 150; } label i { font-size: 15px; font-style: normal; display: inline-block; width: 18px; border-radius: 15px; height: 18

随机推荐