layui-tree 不支持多选权限矩阵,需手动添加 checkbox、状态管理及父子联动逻辑,并通过隐藏域提交选中 ID 数组。

layui-tree 本身不支持多选权限矩阵,得自己加 checkbox + 状态管理
layui 的 tree 组件默认只渲染结构、支持展开/折叠和单点点击,没有内置多选逻辑,更不会自动维护父子联动(比如勾选父节点自动选中所有子节点)。你要的是「权限矩阵」,意味着每个节点都要可独立勾选,且需反映层级关系(如部门 → 岗位 → 操作),这必须靠手动增强。
常见错误现象:tree.render() 后节点上没 checkbox;点了也没状态变化;刷新页面后选中态丢失;父子不同步。
- 必须在
data每个节点对象里显式加checked: true/false字段,否则 tree 渲染时不会初始化勾选态 - 渲染时用
id和pid构建树结构,但 checkbox 的 DOM 需额外注入——推荐在click回调里动态插入,或提前在text字段里拼 HTML(如text: ' 编辑') - 不要依赖
tree.on('click', ...)获取最终选中值,它只返回当前点击节点;得自己遍历整个数据源,用layui.each()提取所有checked: true的id
动态加载部门组织架构时,懒加载子节点必须改源码或封装异步逻辑
原生 tree.js 不带懒加载能力,点击父节点时不会自动请求子部门。你看到的「无限级」只是静态数据全量渲染,一旦部门层级深、节点多,首屏就卡死。
真实使用场景:点击「华北区」才拉「北京分公司」「天津分公司」,再点「北京分公司」才拉其下属「技术部」「市场部」——这需要后端提供按 pid 查询子节点的接口,前端触发时调用。
- 最稳妥做法:不改 layui 源码,而是用
tree.on('click', function(obj){...})拦截点击,判断该节点children为空且有isParent: true字段时,用layui.jquery.get()请求子数据,拿到后调用obj.elem.next('.layui-tree-pack').html(...)手动追加子节点 DOM - 如果非要改源码,重点看
tree.js里的r.render方法,在生成每个节点前加判断:若节点含loadUrl字段,则插入一个带 loading 图标的占位,再异步加载并替换 - 注意缓存:同一
pid的子节点只请求一次,用全局对象如window.treeCache = {}存结果,避免重复拉接口
权限矩阵的父子联动不能靠 CSS 类,得用递归函数同步数据状态
很多人以为给父节点加 layui-this 或 layui-tree-spread 就能联动,其实这只是视觉展开态,和 checkbox 状态完全无关。真正的「全选/半选/取消」必须操作数据源本身,并重新渲染或手动更新 DOM 的 checked 属性。
性能影响明显:1000+ 节点时,每次点击都递归遍历整棵树会卡顿,尤其在低配终端上。
- 写两个工具函数:
checkAllChildren(data, id, checked)(递归设子节点checked)和syncParentStatus(data, id)(向上回溯设父节点为半选/全选/未选) - 半选状态无法用原生 checkbox 表达,得在节点前加自定义图标,比如用
(短横线图标),并监听change事件手动切换 - 提交前别用
$('input[name="perm"]:checked')取值——DOM 可能被懒加载打断,始终以 JS 数据源为准,layui.each(treeData, ...)提取所有checked: true的id数组
和 layui 表单验证、form.val() 集成时,隐藏域是唯一可靠方案
form.val() 完全不识别 tree 里的 checkbox,form.verify() 也不会校验它们。你填完表单点提交,后端收不到任何权限 ID,因为它们根本不在 form 元素的序列化范围内。
容易踩的坑:试图把 checkbox 写进 标签内、用 name="perms"、指望 form.on('submit', ...) 自动收集——全部无效。
- 必须加一个隐藏域:
- 每次 checkbox 状态变更后,立刻执行:
$('#perms-input').val(JSON.stringify(selectedIds)),其中selectedIds是你从树数据里提取的数组 - 页面初始化时,若要回显已分配权限,先用
form.val('formFilter', { perms: [...] })设置表单值,再手动遍历树数据,把对应id的节点checked设为true,最后调用tree.render()或更新 DOM - 别用
lay-verify="required"校验这个隐藏域,它永远有值(空数组也是字符串),校验逻辑得写在 submit 回调里:if (selectedIds.length === 0) { layer.msg('至少选择一项权限'); return false; }
实际复杂点在于:部门树数据格式不统一(有的后端返回扁平列表带 pid,有的直接返回嵌套 JSON),而权限矩阵要求每个节点既要展示名称,又要绑定业务语义(比如「技术部」对应部门 ID、「编辑文档」对应操作 code)。这些字段必须在初始化前对齐,漏一个 id 或类型错成字符串,联动就会断掉。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











