Pretext+原生 JavaScript 高性能虚拟列表,十万数据秒级渲染不卡顿

0 阅读4分钟

在前端开发中,长列表渲染是高频场景:聊天记录、商品列表、日志展示、数据看板……当数据量达到成百上千甚至上万条时,直接渲染所有 DOM 会带来致命问题:

  • 首次渲染白屏、卡顿
  • 滚动掉帧、页面卡死
  • DOM 数量爆炸,内存占用飙升

传统方案要么分页(体验差),要么懒加载(依然会堆积 DOM),而虚拟列表是解决长列表性能问题的最优解。

前几天看到了一个开源的Pretext库,于是就用纯原生 HTML + JavaScript,结合高性能文本计算库 Pretext,实现一套支持动态高度、零回流、上拉加载的高性能虚拟列表,代码可直接商用,十万条数据流畅滚动。


一、什么是虚拟列表?核心原理一句话讲清

虚拟列表 = 只渲染「可视区域 + 少量缓冲区域」的 DOM,其余内容用高度占位撑开滚动条。

它的核心逻辑非常简单:

  1. 计算所有列表项总高度,用一个空节点撑开容器滚动条(用户感知正常滚动)
  2. 监听滚动位置,计算当前可视区域应该显示哪些数据
  3. 只渲染这一小部分数据,滚动时动态更新 DOM
  4. 配合缓冲区,避免滚动时出现白屏

最终效果:无论 1 万条还是 10 万条数据,页面永远只渲染 20~30 个 DOM 节点。


二、本方案核心优势

相比市面上大多数虚拟列表,我们这个原生版本具备顶级性能:

纯原生无依赖:不依赖 Vue/React,直接运行

真正动态高度:支持文本自动换行,精准计算高度

零 DOM 回流:使用 Pretext 纯 JS 计算文本高度,不创建临时 DOM

滚动丝滑无白屏:内置上下缓冲区

上拉加载更多:无缝支持大数据量分页

移动端适配:支持流畅惯性滚动

代码极简可维护:核心逻辑不到 200 行 JS


三、关键技术点解析

1. 动态高度计算(最大痛点解决)

绝大多数虚拟列表只能用固定高度,因为动态高度需要创建 DOM 测量,触发昂贵回流。

我们使用 Pretext:

  • 纯 JavaScript 实现文本布局
  • 基于 Canvas 测量字符宽度 + 数学计算
  • 不操作 DOM、不触发重排
  • 支持中文/英文/混合文本自动换行
  • 计算速度极快,适合大量数据
// 核心:纯 JS 计算列表项高度
function calcItemHeight(item) {
  const prep = prepare(item.content, FONT)
  const { height } = layout(prep, ITEM_WIDTH, LINE_HEIGHT)
  return height + 24 // 文本高度 + 内边距
}

2. 高度缓存机制

  • 首次加载统一计算所有项高度
  • 存入数组缓存,避免重复计算
  • 加载更多时增量缓存
  • 总高度通过数组求和得出

3. 可视区域计算算法

  1. 从顶部累加高度,找到第一个出现在可视区域上方的索引
  2. 减去缓冲条数,得到起始渲染索引
  3. 继续累加,找到可视区域最下方的索引
  4. 加上缓冲条数,得到结束渲染索引
  5. 使用 slice 截取数据,只渲染可视部分

4. 定位优化:transform 替代 top

使用 translateY 移动渲染区域:

  • 浏览器硬件加速
  • 比修改 top 性能高 3~5 倍
  • 滚动极致流畅
listWrapper.style.transform = `translateY(${offsetY}px)`

四、完整可运行代码 可直接访问

image.png www.zybkpro.top/pretext_vir…

原生 JavaScript 高性能虚拟列表,十万数据秒级渲染不卡顿


五、适用场景

  • 后台系统数据表格、日志列表
  • 移动端聊天页、消息流
  • 大数据看板、实时数据展示
  • 商品列表、文件列表
  • 任何需要展示超长列表的场景

六、性能对比(直观感受)

方案1000 条10000 条100000 条
直接渲染 DOM轻微卡顿严重卡顿页面崩溃
普通虚拟列表流畅流畅轻微掉帧
本方案(原生+Pretext)极流畅极流畅丝滑无感知

七、总结

虚拟列表不是高级技巧,而是前端长列表的标准最优实践。 这套原生 JavaScript 虚拟列表实现:

  • 代码极简、易读易改
  • 无框架绑定,可用于任何项目
  • 动态高度支持,真正商用可用
  • 十万数据不卡顿,性能达到业界一流水平

如果你正在面对长列表卡顿问题,直接复制代码即可解决 99% 的性能痛点。