虚拟列表及其原理

一、什么是长列表?
前端的业务开发中会遇到一些数据量较大无法使用分页方式来加载的列表,我们一般把这种列表叫做长列表
完整渲染的长列表基本上很难达到业务上的要求的,非完整渲染的长列表一般有两种方式:

  • 懒渲染:这个就是常见的无线滚动的,每次只渲染一部分(比如10条),等剩余部分滚到可见区域,就再渲染一部分。
  • 可视区域渲染:只渲染可见部分,不可见部分不渲染。

虚拟列表就是采用的可视区渲染方式优化
二、虚拟列表实现原理
虚拟列表(Virtual List),是一种长列表优化方案,是可视区渲染列表。其两个重要的概念:

  • 可滚动区域:假设有1000条数据,每个列表项的高度是30,那么可滚动的区域的高度就是1000*30。当用户改变列表的滚动条的当前滚动值的时候,会造成可见区域的内容的变更。
  • 可见区域:比如列表的高度是300,右侧有纵向滚动条可以滚动,那么视觉可见的区域就是可见区域。

虚拟列表原理:

用数组保存所有列表元素的位置,只渲染可视区内的列表元素,当可视区滚动时,根据滚动的offset大小以及所有列表元素的位置,计算在可视区应该渲染哪些元素。
在这里插入图片描述

三、参考实现
实现虚拟列表就是处理滚动条滚动后的可见区域的变更,具体实现步骤如下

  1. 计算当前可见区域起始数据的startIndex
  2. 计算当前可见区域借宿数据的endIndex
  3. 计算当前可见区域的数据,并渲染到页面中
  4. 计算startIndex对应的数据在整个列表中的偏移位置startOffset,并设置到列表上

做了一个设定:每个列表项的高度都是30px。在这个约定下,核心JavaScript代码不超过10行,但是可以完整的实现可见区域的渲染和更新。

HTML、CSS如何实现,添加了这么几个样式:

  • 列表元素(.list-view)使用相对定位
  • 使用一个不可见元素(.list-view-phantom)撑起这个列表,让列表的滚动条出现
  • 列表的可见元素(.list-view-content)使用绝对定位,left、right、top设置为0
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>简单实现虚拟列表</title>
  </head>
  <style>
    .list-view {
      height: 400px;
      overflow: auto;
      position: relative;
      border: 1px solid #aaa;
    }

    .list-view-phantom {
      position: absolute;
      left: 0;
      top: 0;
      right: 0;
      z-index: -1;
    }

    .list-view-content {
      left: 0;
      right: 0;
      top: 0;
      position: absolute;
    }

    .list-view-item {
      padding: 5px;
      color: #666;
      line-height: 30px;
      box-sizing: border-box;
    }

    [v-cloak] {
      display: none;
    }
  </style>

  <body>
    <div id="app" v-cloak>
      <div class="list-view" ref="scrollBox" @scroll="handleScroll">
        <div
          class="list-view-phantom"
          :style="{
                       height: contentHeight
                    }"
        ></div>
        <div ref="content" class="list-view-content">
          <div
            class="list-view-item"
            :style="{
                        height: itemHeight + 'px'
                      }"
            v-for="item in visibleData"
          >
            {{ item }}
          </div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
    <script>
      new Vue({
        el: "#app",
        computed: {
          contentHeight() {
            return this.data.length * this.itemHeight + "px";
          },
        },
        mounted() {
          this.updateVisibleData();
        },
        data() {
          return {
            data: new Array(100).fill(1),
            itemHeight: 30,
            visibleData: [],
          };
        },
        methods: {
          updateVisibleData(scrollTop = 0) {
            const visibleCount = Math.ceil(
              this.$refs.scrollBox.clientHeight / this.itemHeight
            );
            const start = Math.floor(scrollTop / this.itemHeight);
            const end = start + visibleCount;
            this.visibleData = this.data.slice(start, end);
            this.$refs.content.style.webkitTransform = `translate3d(0, ${
              start * this.itemHeight
            }px, 0)`;
          },
          handleScroll() {
            const scrollTop = this.$refs.scrollBox.scrollTop;
            this.updateVisibleData(scrollTop);
          },
        },
      });
    </script>
  </body>
</html>
  • 13
    点赞
  • 95
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
计算机的虚拟存储器是将较大的程序分割成多个较小的部分,只将其中一部分存放在内存中,其余部分则存储在硬盘等外部存储设备中,需要时再调入内存中进行执行,以达到内存空间利用率最大化和程序执行效率最优化的目的。虚拟存储器的工作原理可以分为以下几个步骤: 1. 程序被分成多个虚拟页:将程序按照固定大小进行划分,每个部分称为一个虚拟页,每个虚拟页的大小与计算机的页大小相同。 2. 虚拟页被映射到物理页:虚拟页与物理内存之间进行映射,每个虚拟页对应一块物理页,物理页的大小与虚拟页的大小相同。 3. 虚拟页被调入内存:当程序需要访问某个虚拟页时,若该虚拟页尚未调入内存,则操作系统将其从外部存储设备中读入内存。 4. 硬件提供地址转换:当程序访问某个虚拟地址时,硬件通过虚拟地址与物理地址之间的映射关系,将虚拟地址转换为物理地址。 5. 调页机制:当内存中没有足够的空间存放新的虚拟页时,操作系统会选择一部分已经在内存中但长时间未被使用的虚拟页将其换出,为新的虚拟页腾出空间。 总之,虚拟存储器通过将程序分割成多个虚拟页,将部分虚拟页存储在内存中,其余部分存储在外部存储设备中,通过地址映射和调页机制,实现了程序的透明访问,并且最大限度地利用了内存空间。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值