权限字段必须由后端返回动作级标识(如can_edit),前端仅渲染与校验;操作列须用templet而非toolbar;按钮禁用仅为视觉限制,事件回调中必须二次校验权限。
权限字段必须在后端返回的数据里,不能只靠全局角色变量
很多人直接在 templet 函数里写 window.user_role === 'admin',结果发现“非本人创建的行也能编辑”。问题出在:全局角色只能判断“你是不是管理员”,但没法回答“这条数据归不归你管”。
- 后端接口必须每条记录都透出权限标识字段,比如
can_edit: true、is_creator: false、status: "draft" - 前端不要在
templet里重复做d.create_by === window.USER_ID这种字符串比对——易错、难调试、改个字段名就全挂 - 如果真要前端计算权限,抽成统一函数,例如
canDo(d, 'edit'),所有列共用一个逻辑入口
操作列按钮必须用 templet,别指望 toolbar 动态控制单行权限
toolbar 是全局的,它拿不到当前行数据 d,所以根本没法根据 d.status 或 d.can_delete 决定某一行该显示什么按钮。硬要用,只会导致所有行按钮一模一样。
- 列配置里删掉
{ fixed: 'right', toolbar: '#barDemo' }这类写法 - 改成
{ field: 'action', title: '操作', templet: '#actionTpl' } - 页面中定义
<script type="text/html" id="actionTpl"></script>模板,里面用{{# if(d.can_edit) { }}...{{# } }}控制渲染 - 按钮必须带
lay-event属性(如lay-event="edit"),否则table.on('tool()')监听不到
禁用按钮 ≠ 安全,事件回调里必须二次校验
模板里写 <button disabled></button> 只是视觉限制,用户删掉 DOM 上的 disabled 属性或用键盘触发,照样能点。这不是前端偷懒,是业务安全底线。
- 所有
table.on('tool(filter)', function(obj){ ... })回调开头,先读obj.data.status或obj.data.can_delete - 不符合条件直接 return,例如:
if (!obj.data.can_delete) { layer.msg('无删除权限'); return; } - 别用
$(obj.tr).find('button')查状态——表格重载后 DOM 已换,查到的是旧引用 - 涉及多条件(如
status === 'published' && can_delete),把判断逻辑单独抽函数,避免复制粘贴出错
fixed 列 + 动态按钮数量 = 必须设固定宽度
当操作列设了 fixed: 'right',且按钮数量不固定(比如有的行显示 1 个“编辑”,有的显示“编辑+下架+复制”3 个),Layui 的表格宽度计算会失准,导致列错位、文字强制换行、甚至右侧滚动条异常。
- 给操作列显式设置
width: 180(单位像素,按最多按钮数预估) - 按钮容器加 class 包裹,例如
<div class="opt-btns">...</div>,方便后续 CSS 微调 - 不要依赖
minWidth,它在 fixed 列里不生效 - 移动端测试时重点看是否溢出或挤压其他列——fixed 列的宽度是刚性的,没弹性空间
真正容易被忽略的,是权限字段的粒度。后端返回一个 role: "editor" 不够,得返回 can_edit: true、can_publish: false 这种动作级标识。前端只负责“照单渲染+照单校验”,别在 JS 里拼权限字符串、做角色继承推导——那不是前端该干的事。











