倒计时渲染必须用templet函数返回实时html并配合统一定时器更新,禁用每行独立setinterval;需在table.done中重初始化,支持reload、分页及页面切换,并推荐用requestanimationframe平滑驱动。
倒计时渲染必须用 templet,不能靠 field 直接绑定
因为 layui 表格的 field 是静态映射字段值,而倒计时是动态变化的,每次重绘都需重新计算剩余时间。必须通过 templet 函数返回实时 html 字符串,并配合定时器驱动更新。
常见错误是把倒计时逻辑写在 data 初始化里,结果只渲染一次就停住——Layui 不会自动重绘单元格内容,得自己管更新节奏。
-
templet返回的内容会被插入到单元格内,可包含id或class用于后续 DOM 定位 - 建议给每个倒计时容器加唯一
id,比如countdown-<em>{id}</em>,避免多个行之间互相干扰 - 不要在
templet里直接调用setInterval,否则每行渲染都会新建一个定时器,内存泄漏风险高
用 layui.laytpl 预编译模板 + 独立定时器管理更可控
把倒计时逻辑从表格渲染中解耦出来,先用 laytpl 生成初始 HTML,再统一用一个全局定时器(如 setInterval(..., 1000))去批量更新所有倒计时 DOM 节点。
这样做的好处是:避免成百个 setInterval 同时运行、CPU 占用高;也方便暂停/销毁(比如切换页签或销毁表格时清除)。
- 在
templet中返回类似<span class="layui-countdown" data-endtime="1717023600000">02:34:18</span> - 初始化后遍历所有
.layui-countdown,解析data-endtime并缓存到数组里 - 用单个
setInterval每秒遍历该数组,计算剩余时间并更新对应innerText - 注意时间戳单位是毫秒,
new Date().getTime()返回的是毫秒,别和秒级时间戳混用
注意表格重载(table.reload())会清空 DOM,倒计时定时器需手动恢复
调用 table.reload() 或分页切换时,整个表格 DOM 会被重建,之前绑定的倒计时节点和定时器引用全部失效。如果不处理,倒计时就“卡死”在旧值上。
- 在
done回调里重新执行倒计时节点扫描和状态同步 - 推荐把倒计时管理逻辑封装成函数,如
initCountdowns(),在render和done中都调用它 - 如果用了
page: false(无分页),也要监听数据变更(如通过table.cache对比),必要时触发重置 - 倒计时结束时建议加个标记类,比如
countdown-ended,方便 CSS 控制样式(如变红、禁用点击)
移动端频繁重绘可能掉帧,用 requestAnimationFrame 替代 setInterval 更稳妥
虽然每秒更新一次倒计时看起来用 setInterval 就够了,但在低端安卓机或微信内置浏览器中,表格滚动+定时器+DOM 更新叠加,容易造成卡顿甚至倒计时跳秒。
更稳的做法是用 requestAnimationFrame 驱动,结合时间差做平滑更新,而不是固定间隔强制刷:
- 记录上一次更新时间戳,在 rAF 回调里算差值,只在差值 ≥1000ms 时才更新显示
- 这样既保证视觉上不跳秒,又避免无谓的 DOM 写操作
- 示例关键片段:
let lastUpdate = Date.now(); function tick() { const now = Date.now(); if (now - lastUpdate >= 1000) { updateAllCountdowns(); // 批量更新 DOM lastUpdate = now; } requestAnimationFrame(tick); } requestAnimationFrame(tick);
真正麻烦的不是写几行倒计时代码,而是表格生命周期和 DOM 变更节奏不一致——得时刻想着“这个节点还在不在”“这次更新要不要跳过”“用户切到别的 tab 了要不要暂停”。这些细节没兜住,倒计时看着就“有时动有时不动”。











