权限控制必须在DOM渲染前按权限筛除结构,而非渲染后删除节点;表格列、工具栏、菜单等均需初始化时依据后端返回的权限数据动态生成,确保数据源头可信且状态一致。

前端不能靠“剔除 DOM 节点”来实现权限控制——这不是安全做法,也破坏 Layui 内部状态。真正该做的是:在 DOM 渲染前,就按权限筛掉不该出现的结构。
为什么不能等渲染完再删 DOM
常见错误是 table 渲染后用 $('th[field="salary"]').closest('th').remove() 或菜单加载后 $('.layui-nav-item:contains("系统设置")').remove()。这会导致:
- 被删节点仍存在于原始配置或数据中,导出、排序、打印、固定列等功能异常
- 右键审查元素仍能看到敏感字段(如
salary、idCard)的残留逻辑 - toolbar 按钮即使隐藏,
lay-event="export"仍可被手动触发 - tab 删除只调
element.tabDelete()不删 DOM,激活态和内容页脱节
表格列(cols)必须初始化前过滤
table.render() 的 cols 是纯配置数组,Layui 不监听其后续变更。删列必须发生在传入前:
- 把列拆成基础列 + 权限列,例如:
const baseCols = [{field: 'name'}, {field: 'dept'}] - 根据
window.USER_ROLE或后端返回的auth字段拼接:if (userRole === 'admin') cols[0].push(...adminCols) - 别用
splice()或delete修改已传入的cols引用——无效 - 含
fixed: 'right'的列必须确保始终在拼接后数组末尾,否则错位
工具栏(toolbar)和操作列按钮要手写 HTML 字符串
toolbar 参数只接受字符串或 DOM 节点,不支持运行时条件渲染。正确路径是:
立即学习“前端免费学习笔记(深入)”;
- 定义按钮配置数组,每个带
role字段:[{id: 'edit', text: '编辑', role: ['admin', 'editor']}] - 用
filter()和map().join('')拼出最终 toolbar 字符串 - templet 中的操作按钮,权限字段(如
d.can_delete)必须由后端返回,不要仅靠全局USER_ROLE判断行级操作 - 按钮的
lay-event值需全局唯一,避免多个按钮共用export导致误触发
左侧菜单必须后端裁剪 + 前端递归渲染
原生 layui.navbar() 不支持三级及权限过滤,且无法绕过前端全量菜单暴露风险:
- 后端接口(如
/api/menu)必须返回已按角色裁剪的嵌套结构,含href、title、children(空数组也要有) - 前端禁止对全量菜单做 JS 过滤——敏感菜单可能从源码泄露
- 手写递归函数生成 HTML,注意 class 必须准确:
<dd><dl class="layui-nav-child">...</dl></dd> - 高亮当前菜单需手动匹配 URL 并向上冒泡加
layui-nav-itemed,不能依赖 navbar 自动逻辑
权限控制的复杂点不在“怎么删”,而在于“删之前的数据源头是否可信”。所有动态结构都依赖初始化时刻的权限快照,异步加载权限再重 render 表格或菜单,必然伴随闪现或状态不一致——这事得前置到页面入口就做完。


















