应避免用 layui.form.render('select') 渲染大量数据,因其同步遍历全部 option 导致卡顿;推荐使用 formselects 启用虚拟滚动,或改用 layui.dropdown 自定义渲染逻辑。

直接用 layui.form.render('select') 会卡死,别这么干
几千条数据塞进原生 <select></select> 然后调 layui.form.render('select'),主线程会同步遍历每一条 <option></option> 构建下拉面板 DOM,1000 条就可能卡住 200ms+,用户点一下要等半秒才弹出。这不是“数据多”的问题,是 Layui 默认把所有选项都渲染成带搜索、高亮、滚动的完整 UI 组件——而你根本不需要它一次性画完全部。
用 formSelects 替代原生 select,开箱即用虚拟滚动
这是最省事也最稳的方案,formSelects 专为大数据多选设计,底层自动启用虚拟滚动(只渲染可视区域约 30 条),2000 条也能保持流畅。关键配置项必须设对:
-
virtualScroll: true—— 必开,否则还是全量渲染 -
maxHeight: '300px'—— 显式限制高度,让虚拟滚动生效 -
pageSize: 50—— 控制每次加载的 chunk 大小,和后端分页对齐 -
search: true—— 搜索触发过滤,避免用户手动滚动找
示例初始化:
formSelects.render('#citySelect', {
data: cityList, // 一次性传入全部 3000 条
virtualScroll: true,
maxHeight: '300px',
search: true,
placeholder: '输入城市名搜索'
});
如果非要自己写,绕过 select 元素,用 layui.dropdown + 自定义列表
原生 select 是性能瓶颈根源,Layui 的 dropdown 支持自定义 content,你可以完全接管 DOM 渲染逻辑:
- 监听搜索框
input事件,用Array.filter()筛数据(加setTimeout防抖 200ms) - 筛选结果超过 50 条时,只往
<ul></ul>插入前 30 条,并显示“共 N 条,已显示前 30” - 滚动时监听
scrollTop,动态计算起始索引,用innerHTML局部替换,比全量重写快 5–8 倍 - 选中后手动更新绑定的隐藏
<input>或data-value,不依赖select.value
注意:dropdown.reloadData()(2.8+)只更新数据不重建 DOM,比 reload() 快 68%,但前提是你的 content 是纯 HTML 字符串而非函数返回值。
后端不分页,前端缓存也没用,5000 条一次性拉下来就是错的
内存占用高、首屏加载慢、且多数用户只选高频项(如“北京”“上海”)。这不是前端能硬扛的问题:
- 有层级结构(省→市→区)?必须三级联动 + 按需请求,绝不能预加载全部
- 无层级但高频项集中?后端加个
is_hot: true字段,前端先拉热榜 100 条,再按需搜 - 真要全量?压缩 JSON + Web Worker 解析,避免阻塞主线程,但依然不如分页来得稳
真正卡顿的从来不是“渲染”,而是“不该一次性做的事却做了”。数据量一过 500 条,就该放弃原生 select 思维。











