AI 助理
备案 控制台
开发者社区 开发与运维 文章 正文

了解虚拟列表背后原理,轻松实现虚拟列表

简介: 在项目中,大数据渲染常常遇到,比如umy-ui(ux-table)虚拟列表table组件,vue-virtual-scroller以及react-virtualized 这些优秀的插件快速满足业务需要。

在项目中,大数据渲染常常遇到,比如umy-ui(ux-table)虚拟列表table组件,vue-virtual-scroller以及react-virtualized 这些优秀的插件快速满足业务需要。


为了理解插件背后的原理机制,我们实现一个自己简易版的虚拟列表,希望在实际业务项目中能带来一些思考和帮助。


正文开始...


虚拟列表是什么


在大数据渲染中,选择一段可视区域显示对应数据。


我们先初步看一个图

f4742c2ebaa569d1c96cdeef4bb17d91.png

在这张展示图中,我们可以看到我们展示的始终是红色线虚线展示的部分,每一个元素固定高度,被一个很大高度的元素包裹着,并且最外层有一个固定的高度容器,并且设置可以滚动。


新建一个index.html对应结构如下

...
<div class="vitual-list-wrap" ref="listWrap">
  <div class="content" :style="contentStyle">
    <div class="item" v-for="(item, index) in list"
         :key="index" :style="item.style">
        {{item.content}}
    </div>
  </div>
</div>

对应的css

*{
  padding:0px;
  margin: 0px;
}
#app {
  width:300px;
  border: 1px solid #e5e5e5;
}
/*外部容器给一个固定的可视高度,并且设置可以滚动*/
.vitual-list-wrap {
  position: relative;
  height: 800px;
  overflow-y: auto;
}
/*真实容器的区域*/
.content {
  position: relative;
}
/*固定高度的每个元素*/
.item {
  height: 60px;
  padding: 10px 5px;
  border-bottom: 1px solid #111;
  position: absolute;
  left:0;
  right: 0;
  line-height: 60px;
}

从对应页面结构与css中我们的思路大致是这样


  • 确定外层固定的高度,并且设置纵向滚动条


  • 真实容器设置相对定位,并且根据显示总数动态设置一个装载容器的高度


  • 每个元素设置绝对定位,且是固定高度


有了对应设置的结构,因为我们每个元素是绝对定位的,所以我们现在的思路就是:


1、确定可视区域item显示的条数limit


2、向上滑动的当前位置起始位最后位置,确定显示元素范围


3、确定每个元素的top,当向上滑动时,确定当前的位置与最后元素的位置索引,根据当前位置与最后元素位置,渲染可视区域


具体逻辑代码如下

<div id="app">
        <h3>虚拟列表</h3>
        <div class="vitual-list-wrap" ref="listWrap">
            <div class="content" :style="contentStyle">
                <div class="item" v-for="(item, index) in list" 
                  :key="index" :style="item.style">
                    {{item.content}}
                </div>
            </div>
        </div>
</div>
<!--引入vue3组件库-->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/3.2.33/vue.global.min.js"></script>
<script src="./index.js"></script>

我们具体看下index.js

// index.js
const { createApp, reactive, toRefs, computed, onMounted, ref } = Vue;
const vm = createApp({
  setup() {
      const listWrap = ref(null);
      const viewData = reactive({
        list: [],
        total: 1000, // 数据总条数
        height: 600, // 可视区域的高度
        rowHeight: 60, // 每条item的高度
        startIndex: 0, // 初始位置
        endIndex: 0, // 结束位置
        timer: false,
        bufferSize: 5 // 做一个缓冲
      });
      const contentStyle = computed(() => {
        return {
          height: `${viewData.total * viewData.rowHeight}px`,
          position: 'relative',
        }
      });
      // todo 设置数据
      const renderData = () => {
        viewData.list = [];
        const {rowHeight, height, startIndex, total, bufferSize} = viewData;
        // 当前可视区域的row条数
        const limit = Math.ceil(height/rowHeight);
        console.log(limit, '=limit');
        // 可视区域的最后一个位置
        viewData.endIndex = Math.min(startIndex + limit + bufferSize, total -1);
          for (let i=startIndex; i<viewData.endIndex; i++) {
            viewData.list.push({
            content: i,
            style: {
              top: `${i * rowHeight}px`
            }
          })
        }
      }
      // todo 监听滚动,设置statIndex与endIndex
      const handleScroll = (callback) => {
        // console.log(listWrap.value)
        listWrap.value && listWrap.value.addEventListener('scroll', (e) => {
          if (this.timer) {
            return;
          }
          const { rowHeight, startIndex, bufferSize } = viewData;
          const { scrollTop } = e.target;
          // 计算当前滚动的位置,获取当前开始的起始位置
          const currentIndex = Math.floor(scrollTop / rowHeight); 
          viewData.timer = true;
          // console.log(startIndex, currentIndex);
          // 做一个简单的节流处理
          setTimeout(() => {
            viewData.timer = false;
               // 如果滑动的位置不是当前位置
               if (currentIndex !== startIndex) {
                viewData.startIndex = Math.max(currentIndex - bufferSize, 0);
                callback();
               }
            }, 500)
        })
      }
      onMounted(() => {
        renderData();
        handleScroll(renderData);
      })
      return {
        ...toRefs(viewData),
        contentStyle,
        renderData,
        listWrap
      }
  },
})
vm.mount('#app')

看下页面,已经ok了,每次上滑都只会固定高度加载对应的数据


8b69691adb675dd7dcd46c577a76311a.png


注意我们在css中有一段这样的代码

#app {
  width:300px;
  border: 1px solid #e5e5e5;
  opacity: 0;
}
...
[data-v-app]{
  opacity: 1 !important;
}

这样处理主要是为了插值表达式在未渲染的时候,让用户看不到未渲染前的模版内容。如果不先隐藏,那么会打开页面的时候会有插值表达式,vue中提供了一个v-cloak,但是貌似这里不管用,在vue2中是可以的。


本篇是非常简易的虚拟列表实现,了解虚拟列表背后的实现思想,更多可以参考vue-virtual-scroller[1]react-virtualized[2]源码的实现,具体应用示例可以查看之前写的一篇偏应用的文章 测试脚本把页面搞崩了 。


总结


  • 了解虚拟列表到底是什么,在大数据渲染中,选择一段可视区域显示对应数据


  • 实现虚拟列表的背后原理,最外层给定一个固定的高度,然后设置纵向Y轴滚动,然后每个元素的父级设置相对定位,设置真实展示数据的高度,根据item固定高度(rowHeight),根据可视区域和rowHeight计算可显示的limit数目。


  • 当滚动条上滑时,计算出滚动的距离scrollTop,通过currentIndex = Math.floor(scrollTop/rowHeight)计算出当前起始索引


  • 根据endIndex = Math.min(currentIndex+limit, total-1)计算出最后可显示的索引


  • 最后根据startIndex与结束位置endIndex,根据startIndexendIndex渲染可视区域


  • 本文示例代码code example[3]


  • 本文参考相关文章如何实现一个高度自适应的虚拟列表[4],这是react版本的
Web技术学苑
目录
相关文章
1387503158665997
|
1月前
|
缓存 Linux 开发工具
虚拟映射的内核栈支持 【ChatGPT】
虚拟映射的内核栈支持 【ChatGPT】
1387503158665997
41 0
球球不吃虾
|
5月前
|
JavaScript 前端开发 算法
深入理解虚拟DOM:原理、优势与实践
深入理解虚拟DOM:原理、优势与实践
球球不吃虾
240 0
91HTTP代理
|
5月前
|
缓存 负载均衡 安全
虚拟 IP 地址对于网络有什么用处?
随着互联网技术和科技的发展,在上网的时候使用代理ip的使用人数也越来越多,因为业务的需求需要使用http动态代理ip的应用范围越来越多,那么http代理ip组成成分有哪些?接下来小编就给大家介绍一下
91HTTP代理
236 0
虚拟 IP 地址对于网络有什么用处?
快乐阿超
|
10月前
|
JavaScript
虚拟列表
虚拟列表
快乐阿超
97 0
非正常攻城狮的学习笔记
|
安全 BI 网络安全
虚拟桌面是如何实现“安全”目标的
在今天的分享中,我们来谈谈“虚拟桌面”。首先,非常感谢亚信安全技术专家方锦鹏先生,提供亚信安全产品的咨询和支持,帮助我一起搭建了一个用于本次公众号分享的演示环境。
非正常攻城狮的学习笔记
170 0
虚拟桌面是如何实现“安全”目标的
珞瑜
|
数据可视化 vr&ar 计算机视觉
使用标记增强技术将虚拟内容呈现到现实场景中
使用基于标记的增强现实将虚拟内容呈现到场景中。
珞瑜
164 0
游客jfclsu2z7ufhs
|
存储
西门子S7-1200分配列表如何使用
今天我们来讲一下西门子S7-1200分配列表如何使用。
游客jfclsu2z7ufhs
236 0
西门子S7-1200分配列表如何使用
猫先生c
|
JavaScript 数据可视化 索引
列表无限滚动(虚拟列表)
列表无限滚动(虚拟列表)
猫先生c
297 0
列表无限滚动(虚拟列表)
阿里云社区
|
开发框架 JavaScript 前端开发
虚拟 DOM 的本质和目的|学习笔记
快速学习虚拟 DOM 的本质和目的
阿里云社区
131 0
虚拟 DOM 的本质和目的|学习笔记
开发者小助理
|
开发框架 JavaScript 前端开发
虚拟DOM的本质和目的
一、虚拟DOM的介绍 二、DOM的本质 三、react中的虚拟DOM 四、虚拟DOM的目的 五、虚拟DOM的原理流程 六、虚拟DOM示例 七、DOM与虚拟DOM的区别
开发者小助理
259 0
虚拟DOM的本质和目的

热门文章

最新文章

  • 1
    SpringBoot前后端分离项目,打包、部署到服务器详细图文流程
  • 2
    表格存储新手指南:如何实现分页查询
  • 3
    Kubernetes全方位日志采集与管理的最佳实践 资料下载
  • 4
    高效运维之Docker持续部署图文详解
  • 5
    麒麟开源堡垒机安装部署测试及优缺点总结
  • 6
    5分钟构建API接口服务 | python小知识
  • 7
    阿里建“猫茂”线下购物中心,将实现新零售技术的真正落地
  • 8
    [20180202]脏块写盘问题.txt
  • 9
    通过扩展改善ASP.NET MVC的验证机制[实现篇]
  • 10
    下载后自动打开(更改IE下载文件后的默认处理方法)
  • 1
    14 款超赞的代码片段生成工具😍(程序员必备)
    22
  • 2
    Go语言项目高效对接SQL数据库:实践技巧与方法
    16
  • 3
    用来用去还是用回了ueditor-Vue富文本编辑器二次扩展
    19
  • 4
    uniapp uview扩展u-picker支持日历期间 年期间 月期间 时分期间组件
    20
  • 5
    electron-updater实现electron全量版本更新
    19
  • 6
    electron多标签页模式更像客户端
    15
  • 7
    UniApp低代码-颜色选择器diy-color-picker-代码生成器
    12
  • 8
    低代码开发工具-学生管理系统-老师管理增删改查实现
    12
  • 9
    Vue3商品SKU多规格编辑组件
    13
  • 10
    JavaScript中的面向对象编程(OOP) - 终极指南
    12
  • 相关电子书

    更多
  • 动态、高效,蚂蚁动态卡片的内核逻辑
  • 又快又稳:阿里云下一代虚拟交换机解析
  • 虚拟数字人视频创作产品分享
  • 下一篇
    阿里云无影AI云电脑亮相 体验大幅升级

    深圳坪山网站建设公司灯塔优化网站排名浙江省优化营商环境网站寮步网站关键词优化哪家好专科医院网站优化服务南宁网站优化步骤玩具网站优化策划书万江网站关键词优化多少钱德州济南网站优化机构南阳整站seo网站优化推广网站优化公司方案移动网站seo优化栖霞区怎么做网站优化酒泉网站怎么优化江门网站优化渠道旅游交通优化网站网站搜索引擎优化免费提供试用邯郸家具行业网站优化推广技巧关键词网站优化的意义网站优化推广外包找哪家孝感专业网站优化周口网站优化价格实惠大连整站网站优化网站的搜索优化是什么意思seo网站优化价格是多少钱宁波网站优化外包化州网站排名优化襄阳网站优化网站优化作弊宝鸡网站优化培训大连网站长尾关键词优化香港通过《维护国家安全条例》两大学生合买彩票中奖一人不认账让美丽中国“从细节出发”19岁小伙救下5人后溺亡 多方发声卫健委通报少年有偿捐血浆16次猝死汪小菲曝离婚始末何赛飞追着代拍打雅江山火三名扑火人员牺牲系谣言男子被猫抓伤后确诊“猫抓病”周杰伦一审败诉网易中国拥有亿元资产的家庭达13.3万户315晚会后胖东来又人满为患了高校汽车撞人致3死16伤 司机系学生张家界的山上“长”满了韩国人?张立群任西安交通大学校长手机成瘾是影响睡眠质量重要因素网友洛杉矶偶遇贾玲“重生之我在北大当嫡校长”单亲妈妈陷入热恋 14岁儿子报警倪萍分享减重40斤方法杨倩无缘巴黎奥运考生莫言也上北大硕士复试名单了许家印被限制高消费奥巴马现身唐宁街 黑色着装引猜测专访95后高颜值猪保姆男孩8年未见母亲被告知被遗忘七年后宇文玥被薅头发捞上岸郑州一火锅店爆改成麻辣烫店西双版纳热带植物园回应蜉蝣大爆发沉迷短剧的人就像掉进了杀猪盘当地回应沈阳致3死车祸车主疑毒驾开除党籍5年后 原水城县长再被查凯特王妃现身!外出购物视频曝光初中生遭15人围殴自卫刺伤3人判无罪事业单位女子向同事水杯投不明物质男子被流浪猫绊倒 投喂者赔24万外国人感慨凌晨的中国很安全路边卖淀粉肠阿姨主动出示声明书胖东来员工每周单休无小长假王树国卸任西安交大校长 师生送别小米汽车超级工厂正式揭幕黑马情侣提车了妈妈回应孩子在校撞护栏坠楼校方回应护栏损坏小学生课间坠楼房客欠租失踪 房东直发愁专家建议不必谈骨泥色变老人退休金被冒领16年 金额超20万西藏招商引资投资者子女可当地高考特朗普无法缴纳4.54亿美元罚金浙江一高校内汽车冲撞行人 多人受伤

    深圳坪山网站建设公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化