必须放弃 type: "checkbox" 改用自定义模板:表头用独立 checkbox,数据行用 templet 渲染带 disabled 的 input,并手动管理 LAY_CHECKED 状态与缓存过滤。

做不到“表头有全选框、数据行部分禁用”且完全依赖内置 type: "checkbox" 的组合。Layui 的 type: "checkbox" 是整列行为,无法拆解为“表头独立控制 + 行级条件禁用”。必须放弃默认 checkbox 列,改用自定义模板 + 手动状态管理。
为什么不能直接用 type: "checkbox" + checkRender
内置 type: "checkbox" 渲染的表头复选框和所有数据行复选框是强绑定的:点击表头即全选/取消当前页全部行,无法跳过禁用项;checkRender(Layui ≥2.8.0)仅能控制视觉渲染,不参与 table.checkStatus() 识别,也不影响点击逻辑。禁用某几行后,全选操作仍会尝试设置它们的 LAY_CHECKED 状态,导致 checkStatus().data 混入无效数据。
正确做法:表头用自定义 checkbox + 数据行用 templet 渲染带 disabled
核心是分离控制权——表头 checkbox 不走 Layui 内部事件流,数据行 checkbox 不依赖 type: "checkbox",全部由你手动控制。
- 在
cols中去掉{type: "checkbox"},改为普通列,例如:{field: "select", title: '<input type="checkbox" id="head-check">', width: 50, unresize: true} - 数据行用
templet渲染真实<input type="checkbox">,并显式写disabled和checked:<script type="text/html" id="row-checkbox"> <input type="checkbox" name="layTableCheckbox" {{# if(d.status === 'closed'){ }} disabled {{# } }} {{# if(d.LAY_CHECKED){ }} checked {{# } }}> </script> -
name="layTableCheckbox"必须保留,这是 Layui 内部识别多选行的硬性约定,否则table.checkStatus()拿不到该行 - 在
done回调中绑定表头 click 事件,并只操作当前页缓存中的有效行:done: function(res, curr, count){ const cache = table.cache['yourTableId'] || []; const validRows = cache.filter(d => d.status !== 'closed'); $('#head-check').on('change', function(){ const checked = this.checked; // 只勾选/取消 validRows 对应的行 $('tr[data-index]').each(function(i){ const d = cache[i]; if (d && d.status !== 'closed') { const cb = $(this).find('input[name="layTableCheckbox"]'); if (cb.length) cb.prop('checked', checked); } }); // 手动触发 layui checkbox 重绘(可选) layui.form.render('checkbox'); }); }
如何确保 table.checkStatus() 返回干净结果
即使你手动控制了 DOM 状态,table.checkStatus('yourTableId') 仍会返回所有行(含被 disabled 的),因为 Layui 不自动过滤 disabled 行。你必须自己筛:
- 先取缓存:
const cache = table.cache['yourTableId'] - 再过滤出真正有效的已勾选数据:
cache.filter(d => d.status !== 'closed' && d.LAY_CHECKED) - 注意字段名是
LAY_CHECKED(大写),不是你传入的layChecked或其他别名 - 如果需要判断“是否全选”,不要看
res.count,而要比较:validChecked.length === validRows.length
最易忽略的是:每次 table.reload() 后,cache 会刷新,但你模板里写的 disabled 和 checked 仅基于当前数据快照。如果禁用逻辑依赖异步状态(比如权限接口返回后才知某行是否禁用),必须在 done 回调里同步更新 cache[i].LAY_DISABLED = true 并重设 LAY_CHECKED,否则翻页或重载后禁用失效。


















