好家伙,

 

1. 什么是虚拟列表

虚拟列表(Virtual List)是一种优化长列表渲染性能的技术。当我们需要展示成千上万条数据时,如果一次性将所有数据渲染到DOM中,会导致页面卡顿甚至崩溃。虚拟列表的核心思想是:只渲染可视区域内的数据,而不是渲染所有数据

 

2. 使用场景

虚拟列表适用于以下场景:

  • 大数据量展示:如聊天记录、新闻列表、商品列表等需要展示大量数据的场景
  • 无限滚动:需要支持用户持续滚动加载更多内容的场景
  • 性能敏感:在低性能设备上运行的应用,需要尽可能减少DOM操作
  • 实时数据更新:频繁更新的数据列表,如股票行情、实时监控数据等

(我觉得实际场景中,分页会用到更多,用户要看的数据,永远只是一小部分,就那么几条,找不到就用搜索

但总要学学)

 

3. 虚拟列表原理

一句话:

要看了,再渲染

对,就这么简单,下面,进行分步

  • 计算可视区域:确定用户当前可以看到的视口范围
  • 计算可见项:根据视口位置、每项高度,计算出当前应该显示哪些数据项
  • 渲染可见项:只渲染计算出的可见项到DOM中
  • 位置偏移:通过CSS定位,确保可见项在正确的位置显示
  • 监听滚动:当用户滚动时,重新计算可见项并更新DOM

这里几个难点:
我怎么知道哪些数据进入了可视区域?
答:监听滚动距离,滚到哪,就从哪里开始

 

 

4. 实现虚拟列表

Demo.html代码如下:

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>原生JavaScript虚拟列表实现</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
} .list-container {
position: relative;
height: 400px;
overflow: auto;
border: 1px solid #ccc;
margin: 20px auto;
width: 80%;
} .list-phantom {
position: absolute;
left: 0;
top: 0;
right: 0;
z-index: -1;
} .list-content {
position: absolute;
left: 0;
right: 0;
top: 0;
overflow: hidden;
} .list-item {
padding: 10px;
border-bottom: 1px solid #eee;
color: #666;
} .list-item:hover {
background-color: #f5f5f5;
}
</style>
</head>
<body>
<h1 style="text-align: center; margin: 20px 0;">原生JavaScript虚拟列表</h1>
<div id="virtualList" class="list-container">
<div class="list-phantom"></div>
<div class="list-content"></div>
</div> <script>
class VirtualList {
constructor(options) {
this.container = options.container;
this.data = options.data || [];
this.itemHeight = options.itemHeight || 50;
this.bufferSize = options.bufferSize || 5; this.phantom = this.container.querySelector('.list-phantom');
this.content = this.container.querySelector('.list-content'); this.startIndex = 0;
this.endIndex = 0;
this.scrollTop = 0; this.init();
} init() {
// 设置占位容器的高度
this.phantom.style.height = this.data.length * this.itemHeight + 'px'; // 监听滚动事件
this.container.addEventListener('scroll', this.handleScroll.bind(this)); // 初始渲染
this.updateVisibleItems();
} handleScroll() {
// 获取当前滚动位置
this.scrollTop = this.container.scrollTop; // 更新可见项
this.updateVisibleItems();
} updateVisibleItems() {
// 计算开始和结束索引
this.startIndex = Math.floor(this.scrollTop / this.itemHeight);
this.endIndex = this.startIndex + Math.ceil(this.container.clientHeight / this.itemHeight); // 添加缓冲区
this.startIndex = Math.max(0, this.startIndex - this.bufferSize);
this.endIndex = Math.min(this.data.length, this.endIndex + this.bufferSize); // 计算偏移量
const offsetY = this.startIndex * this.itemHeight; // 设置内容容器的偏移
this.content.style.transform = `translateY(${offsetY}px)`; // 渲染可见项
this.renderItems();
} renderItems() {
// 清空内容容器
this.content.innerHTML = ''; // 渲染可见项
for (let i = this.startIndex; i < this.endIndex; i++) {
const item = document.createElement('div');
item.className = 'list-item';
item.innerHTML = this.renderItemContent(this.data[i], i);
item.style.height = this.itemHeight + 'px';
this.content.appendChild(item);
}
} renderItemContent(item, index) {
return `<div>索引: ${index}, 内容: ${item}</div>`;
}
} // 生成测试数据
const data = Array.from({ length: 10000 }, (_, i) => `列表项 ${i + 1}`); // 初始化虚拟列表
const virtualList = new VirtualList({
container: document.getElementById('virtualList'),
data: data,
itemHeight: 50,
bufferSize: 10
});
</script>
</body>
</html>

 

5.最后总结

为什么滚动到指定位置后会将对应区域数据渲染?

1.监听滚动事件

2.滚动触发数据更新方法

3.根据滚动距离计算当前数据索引

4.根据可视区域计算要渲染数据项

5.渲染数据

6.定位内容

 

原生JS实现虚拟列表(不使用Vue,React等前端框架)的更多相关文章

  1. 原生js移动端列表无缝间歇向上滚动

    在项目开发中尤其是在项目的活动页面的开发中,经常需要将用户的购买信息或中奖信息等以列表的形式展示在页面当中,并可以使其自动间歇向上滚动来达到在有限的区域内展示所有信息的目的.通常的做法是通过将列表父元 ...

  2. 手把手教你使用Vue/React/Angular三大框架开发Pagination分页组件

    DevUI是一支兼具设计视角和工程视角的团队,服务于华为云DevCloud平台和华为内部数个中后台系统,服务于设计师和前端工程师.官方网站:devui.designNg组件库:ng-devui(欢迎S ...

  3. 从DOM操作看Vue&React的前端组件化,顺带补齐React的demo

    前言 接上文:谈谈我对前端组件化中“组件”的理解,顺带写个Vue与React的demo 上次写完博客后,有朋友反应第一内容有点深,看着迷迷糊糊:第二是感觉没什么使用场景,太过业务化,还不如直接写Vue ...

  4. angular vue react web前端三大主流框架的对比

    首先,我们先了解什么是MVX框架模式? MVX框架模式:MVC+MVP+MVVM 1.MVC:Model(模型)+View(视图)+controller(控制器),主要是基于分层的目的,让彼此的职责分 ...

  5. 原生js实现音乐列表(隔行换色、全选)

    一.实现原理: 1.使用 % 运算符实现各行换色,规律:当%前面的值和后面的值相同时  结果为0: 2.使用开关思想,实现在同一个元素上反复点击时的条件判断,并且把开关以属性方式绑定在每个元素上: 3 ...

  6. vue项目使用前端框架开发,实现滑动效果,若不刷新页面则无法达到预期效果的问题及解决方法

    滑动等效果的初始化时机很重要,在vue项目开发中,需到mounted()钩子函数 (当组件中的DOM结构被渲染好并放到页面中后,会执行这个钩子函数,此时即可初始化滑动效果的js代码). 若组件未挂载到 ...

  7. 手把手教你使用VUE+SpringMVC+Spring+Mybatis+Maven构建属于你自己的电商系统之vue后台前端框架搭建——猿实战01

            猿实战是一个原创系列文章,通过实战的方式,采用前后端分离的技术结合SpringMVC Spring Mybatis,手把手教你撸一个完整的电商系统,跟着教程走下来,变身猿人找到工作不是 ...

  8. 原生JS实现树状结构列表

    树状结构列表,这个技术点之前有写过了,是基于vue讲解,但似乎都没有解决痛点,最基础的原生JS该怎么实现呢? 这篇文章会全面详细的介绍树状结构列表的实现,从数据处理成树状结构,到动态生成dom节点渲染 ...

  9. 导航栏中各按钮在点击当前按钮变色其他按钮恢复为原有色的实现方法(vue、jq、原生js)

    一.vue如何实现? 代码: <!DOCTYPE html> <html lang="en"> <head> <meta charset= ...

  10. vue实现实时监听文本框内容的变化(最后一种为原生js)

    一.用watch方法监听这个变量. <!DOCTYPE html> <html> <head> <meta charset="utf-8" ...

随机推荐

  1. Qt音视频开发1-vlc解码播放

    一.前言 最开始接触视频监控这块的时候,用的就是vlc作为解码的内核,主要是因为vlc使用简单方便,直接传入一个句柄即可,简单几行代码就可以实现一个视频流播放,很适合初学者使用,也推荐初学者用qt+v ...

  2. Ubuntu 20.04编译opencv-3.1.0时报错 error: 'CODEC_FLAG_GLOBAL_HEADER' was not declared in this scope

    Ubuntu 20.04源码编译安装opencv320 报错 error: 'CODEC_FLAG_GLOBAL_HEADER' was not declared in this scope的解决办法 ...

  3. 记录vue和element-ui导出表格到excell

    1.安装插件 npm install 'file-saver' npm install 'xlsx' 2.引入插件 import FileSaver from 'file-saver' import ...

  4. linux 手动释放内存

    在 Linux 系统中,内存管理通常由系统自动处理,但在某些情况下,手动释放内存可能是必要的.例如,当业务应用比较繁忙时会频繁存取文件,物理内存会被缓存大量占用,有时会出现内存不足的情况发生,甚至会导 ...

  5. elsa工作流-调度(安排后台作业)

    前言 elsa内部很多地方都会用到后台作业,也就是在后台线程中执行一堆任务,这与我们通常理解的后台作业没有区别. elsa将后台作业也称为调度Schedul,相关功能由Elsa.Scheduling模 ...

  6. LOL(英雄联盟) API 接口

    /*LOL(英雄联盟) API 接口 By wgscd /*LOL(英雄联盟) API 接口 By wgscd QQ:1009374598 */ GET https://127.0.0.1:58182 ...

  7. MAUI APK安装到其他手机闪退问题

    在本地VS调试一切正常的,生成的APK安装到其他手机 发生闪退了 先是用abd连接 检查日志看: adb -s 192.168.1.10 logcat -v time > e:\log.txt ...

  8. flink基础教程

    随着大数据技术在各行各业的广泛应用,要求能对海量数据进行实时处理的需求越来越多,同时数据处理的业务逻辑也越来越复杂,传统的批处理方式和早期的流式处理框架也越来越难以在延迟性.吞吐量.容错能力以及使用便 ...

  9. OxyPlot:一个功能强大、漂亮.Net跨平台开源绘图库

    推荐一个支持多平台.多框架的.Net绘图库. 01 项目简介 OxyPlot是一个基于.NET开发的.跨平台的绘图库,可用于多种平台和框架,如WPF.Windows 8.Windows Phone.W ...

  10. LeetCode刷题:runtime error: reference binding to null pointer of type 'int' (stl_vector.h)报错请教

    题目:https://leetcode.cn/problems/merge-intervals/ 错误代码: // 思路初探:做了很多道类似区间操作的题目了.本题就是尽可能少的创建新区间 // 1.首 ...