必须设置 height 才能触发 Layui 2.8 表格的原生虚拟滚动,否则即使数据量大也会全量渲染导致卡顿;虚拟滚动与分页机制独立,url 模式配合后端分页才是万级数据最优解。
必须设 height 才能触发 Layui 原生虚拟滚动
layui 2.8 的 table.render() 只有在明确设置了 height(如 height: 500 或 height: 'full-200')时,才会启用内部的虚拟滚动机制。不设 height,哪怕数据有一万行,它也照常全量渲染 tr 节点,页面必卡死。
常见错误是只配了 page: true 就以为“分页=性能优化”,其实那是后端分页逻辑,和前端 DOM 渲染无关。虚拟滚动和分页是两套独立机制:一个管可视区 DOM 数量,一个管数据请求范围。
-
height必须是数字或合法 CSS 高度值,不能是'auto'或未设置 - 若用
'full-xxx',确保父容器有明确高度(如html, body { height: 100%; }),否则计算失效 - 开启后,Layui 会自动计算可视行数、监听
scroll、复用tr节点——你不用写一行滚动监听代码
url 模式 + 后端分页才是万级数据的正解
本地 data: [...] 模式加载万条数据,即使开了 height,首次渲染仍要遍历全部数组生成缓存结构(比如排序索引、templet 执行),内存和主线程压力依然很大。真正轻量的方案是让后端按需吐数据。
关键配置要对齐:
-
url: '/api/list'—— 必须走接口,别传本地大数组 -
page: true—— 启用 Layui 分页器(不是可选,是必须,否则height虚拟滚动在 url 模式下可能不生效) -
request: { pageName: 'pageNum', limitName: 'pageSize' }—— 和后端约定好参数名,避免前端自己拼 query -
response: { countName: 'total', dataName: 'rows' }—— 明确告诉 Layui 哪个字段是总条数、哪块是当前页数据
注意:done 回调里别对 res.data 做 map 或深拷贝,那会额外触发 GC,大数据场景下这一步就能拖慢 100ms+。
禁用函数模板、简化列配置能再省 30% 渲染时间
Layui 对每列的 templet 函数是逐行调用的。一万行 = 一万次 JS 函数执行 + 字符串拼接。换成字符串模板,直接由内部正则替换,快一个数量级。
- 把
templet: function(d) { return '<span>'+ d.name +'</span>'; }改成templet: '{{=d.name}}'或外部模板templet: '#nameTpl' - 删掉所有没用的列属性:
style、event、unresize(除非真需要),每个字段都会进initOpts的初始化流程 - 用
cellMinWidth: 60全局设最小宽,别每列写minWidth: 60,减少样式计算次数 - 避免
skin: 'line'或'row',默认'default'最轻量
自定义事件绑定必须用原生 addEventListener
虚拟滚动会动态替换 tbody.innerHTML,所有之前用 table.on('tool(demo)', ...) 绑定的事件监听器都会失效——因为 DOM 节点被整个替换了。
正确做法是手动委托到 tbody,并利用 data-index 定位原始数据:
const tbody = document.querySelector('#demo tbody');
tbody.addEventListener('click', function(e) {
const tr = e.target.closest('tr');
if (!tr) return;
const index = +tr.dataset.index; // 注意是字符串,要转数字
const rowData = allData[index]; // allData 是你维护的原始数组
console.log('点击了第', index, '行', rowData);
});
如果用了复选框列(type: 'checkbox'),状态不能靠 tr.querySelector('input').checked 读取,得单独用 Map 或数组维护勾选状态,否则滚动后状态就丢了。
虚拟滚动不是开关一开就万事大吉。height 值太小会导致频繁重绘,太大又浪费内存;后端返回的每页数据量(limit)最好和可视行数接近,否则空滚动明显;排序、搜索后记得调用 table.reload() 并重置 scrollTop,不然用户会卡在旧位置看不到新数据。


















