layui table 原生不支持列宽调整事件,唯一稳定捕获方式是为每个 th 单独配置 mutationobserver 监听 style.width/minwidth 变更,并用 getcomputedstyle(th).width 读取真实宽度存 localstorage。
layui table 原生根本没有列宽调整后的事件,table.on('resize') 或 table.on('columnresize') 会静默失败或直接报错——这不是你配置错了,是它压根不存在。
为什么 MutationObserver 是唯一能稳定捕获列宽变化的方式
用户拖拽分隔线时,Layui 实际只做一件事:同步修改对应 th 元素的 style.width 或 style.minWidth。这个操作不封装、不节流、不发事件,所以监听 DOM 属性变更就是最贴近真实行为的路径。
- 不能靠
mousedown/mouseup:分隔线是伪元素::after,无法绑定事件;也找不到拖拽结束时对应的是哪一列 - 别用轮询
getComputedStyle:性能差,容易漏判,且触发时机不可控 - 不要监听整个
thead:里面太多无关变动(比如排序箭头 class 切换),过滤成本高还易误触 - 必须在
done回调里为每个th单独创建MutationObserver实例,避免互相干扰
如何正确读取拖拽后的真实列宽值
直接读 th.style.width 不可靠:Layui 有时写 min-width,有时留空,有时带单位("120px")。应统一用 getComputedStyle(th).width 获取最终渲染宽度。
- 用
th.dataset.field或th.innerText区分列上下文,避免存错字段 - 拿到宽度后立刻存
localStorage,例如:localStorage.setItem(`table-col-width-${field}`, width) - 注意单位:
getComputedStyle返回的是带px的字符串,如需纯数字,用parseInt(width) - 如果列配置用了
minWidth,还原时优先覆盖minWidth字段,而不是width
常见错误与兼容性雷区
这个方案在 Layui 2.8.x 至当前最新版均有效,但极易在以下环节翻车:
- 在
render外部或init阶段就查.layui-table th—— 此时 DOM 还没生成,querySelectorAll返回空数组 - 没加防抖:连续拖拽会高频触发,建议在
MutationObserver回调里套一层setTimeout(..., 50) - 移动端无 mouse 事件:如果需要支持触屏,得额外监听
touchstart/touchmove/touchend,且拖拽热区至少设为44×44px - 高 DPI 屏幕或缩放非 100% 时,
mouseup瞬间读值可能滞后:加setTimeout(() => { /* 读宽 */ }, 16)等一帧渲染完成再取
真正麻烦的不是监听本身,而是每次拖完都要手动存、下次渲染前手动读、还要处理多表隔离和 key 冲突——这些逻辑没人帮你兜底,Layui 就是这么“干净”。











