Layui如何解决表格在大数据量万级以上的渲染闪烁

作者:袖梨 2026-07-23
layui.table渲染万级数据闪烁的本质是DOM批量重绘与响应式劫持叠加所致;必须关闭height未设值、page为false、loading:true三项默认行为,并在done回调中用DocumentFragment批量插入tbody,后端必须分页返回数据。

为什么 layui.table 渲染万级数据会闪烁

本质是 dom 批量重绘 + vue 式响应式劫持的叠加效应。layui 2.8+ 虽改用原生 js,但 table.render() 默认仍把全部数据塞进 tbody,浏览器要一次性生成上万个 tr 节点,触发强制同步布局(layout)和重绘(paint),肉眼就看到“白屏→闪一下→出来”。更麻烦的是,如果启用了 evenskin 或自定义 templet,每个单元格还要走一遍字符串拼接或函数调用,cpu 时间直接拉满。

必须关掉的三个默认行为

不关它们,加再多优化都是白搭:

  • height 设为具体数值(如 height: 500),否则表格无法启用虚拟滚动,scrollY 机制压根不生效
  • page 必须设为 true,且 limit 控制在 50–100;万级数据不分页,table.reload() 时仍会全量重绘
  • 禁用 loading: true 的默认动画——它底层用 setTimeout 插入 loading dom,和真实渲染竞争 DOM 树,反而加剧抖动

done 回调接管渲染时机

别依赖 table.render() 自动完成,万级数据下它的内部 render 流程不可控。把实际插入逻辑挪到 done 里,等 layui 完成表头、分页器等轻量结构后再动手:

table.render({  elem: '#demo',  height: 500,  url: '/api/list',  page: true,  limit: 80,  done: function(res, curr, count) {    // 此时表头、分页已就位,只操作 tbody    const tbody = this.elem.next('.layui-table-box').find('tbody');    tbody.empty(); // 清空可能残留的 loading 占位    // 这里可手写字符串拼接,或用 DocumentFragment 批量 append    const frag = document.createDocumentFragment();    res.data.forEach(row => {      const tr = document.createElement('tr');      tr.innerHTML = `<td>${row.id}</td><td>${row.name}</td>`;      frag.appendChild(tr);    });    tbody[0].appendChild(frag);  }});

后端必须配合做分页,前端别硬扛

这是最容易被忽略的「假优化」:有人试图用 data 传入全部万条数据,再靠 page: true 前端切片——layui 内部仍会遍历整个数组做字段映射、格式化、筛选,内存占用翻倍,GC 频繁导致卡顿更明显。

  • 后端接口必须支持 pagelimit 参数,只返回当前页数据
  • 避免在 templet 里调用异步函数(比如查用户头像),这会让每一行都触发微任务,渲染队列崩坏
  • 如果真需要全局搜索,用服务端模糊查询,别把全量数据 load 到前端再 filter

真正卡住的从来不是 layui,是没切断数据流的源头。后端少吐一条无效字段,比前端加十个 debounce 都管用。

相关文章

精彩推荐