必须用templet自定义checkbox列:保留name="layTableCheckbox",动态写disabled和checked属性,用d.LAY_CHECKED读取状态,导出前需手动过滤禁用行,事件中须拦截obj.disabled。

必须用 templet 自定义 checkbox 列,不能依赖 type: 'checkbox'
内置 type: 'checkbox' 列不支持按行禁用,写 disabled: true 在数据里完全无效。唯一可靠方式是删掉该列,改用普通列 + templet 手动生成 <input type="checkbox">。关键点有三个:name="layTableCheckbox" 必须保留(Layui 内部识别多选的硬性约定)、disabled 属性必须根据当前行数据动态写、checked 也得显式控制,不能只靠 d.layChecked 字段自动映射。
- 模板中禁用逻辑必须基于
d(如{{# if(d.status === 'closed'){ }} disabled {{# } }}),不能用外部变量或异步状态 - 字段名要用
d.LAY_CHECKED(不是d.layChecked)来读取 Layui 内部真实选中状态 - 建议加上
lay-id="{{d.id}}",避免某些版本漏触发事件
table.checkStatus() 返回结果包含被禁用的行,必须手动过滤
Layui 不会跳过 disabled 的复选框——table.checkStatus('demo').data 仍会把它们全塞进来。你拿到的“已勾选数据”其实是假的,导出或提交前不处理,禁用行就真被发出去了。
- 先取缓存:
const cache = table.cache['demo'] - 再过滤真正可选且已勾选的行:
cache.filter(d => d.status !== 'closed' && d.LAY_CHECKED) - 判断是否“全选”不能看
res.count,得比对:validChecked.length === cache.filter(d => d.status !== 'closed').length - 启用了
checkStrictly: true也不影响这个过滤逻辑
监听 checkbox 事件时必须拦截禁用项
光加 disabled 属性不够。用户点击全选框后,禁用行的 checkbox 状态不会变,但 table.on('checkbox(test)') 仍可能触发(取决于是否真渲染了 input)。后续逻辑若没拦住,禁用行就会参与批量操作。
- 在事件回调开头加判断:
if(obj.disabled) return; - 别用
pointer-events: none替代disabled:键盘 Space 仍可切换、无障碍支持差、checkStatus结果错误 - 如果用了自定义操作列(如
lay-event="edit"),记得在tool回调第一行加layui.stope(event),否则点击按钮也会触发行选中
禁用只是 UI 层遮蔽,Layui 状态管理完全 unaware
这是最易被忽略的一点:Layui 的内部状态(包括 LAY_CHECKED 字段、全选标记、父子联动)对 disabled 完全无感。它只认 DOM 元素是否存在、是否带 checked,不关心是否被禁用。所以所有业务逻辑都得自己兜底——渲染时控制属性、事件时拦截、取数时过滤、判断全选时比数量。没有哪一步能省。


















