在管理后台系统的开发中,表格行级权限控制是一个高频需求场景。想象这样一个画面:订单管理员需要批量操作待审核订单,但系统要求已完成的订单不可被选中;或者数据审核员需要勾选多条记录进行批量审批,但已锁定的数据行必须禁用选择。这类业务逻辑如果全部用v-if和methods中的条件判断堆砌,代码很快就会变得难以维护。
Element UI的selectable属性正是为解决这类问题而生。这个隐藏在表格选择列中的配置项,能够将复杂的业务规则封装成简洁的函数,实现真正的声明式权限控制。下面我们就从实战角度,剖析如何用这个属性打造优雅的权限控制方案。
selectable是el-table-column组件中type="selection"列的一个函数属性,它接收两个参数:当前行数据row和行索引index,需要返回一个布尔值决定该行是否可选。其核心优势在于:
javascript复制:selectable="(row, index) => row.status !== 'locked'"
这种设计实现了权限判断与UI渲染的解耦。对比传统方式,开发者通常需要在模板中写大量条件渲染:
html复制<el-checkbox
v-if="row.status !== 'locked' && hasPermission('edit')"
v-model="selectedItems"
/>
这种模式存在三个明显缺陷:
而selectable的方案将判断逻辑集中处理,具有以下特点:
| 特性 | 传统方式 | selectable方案 |
|---|---|---|
| 逻辑位置 | 分散在模板和方法中 | 集中在一个函数 |
| 可维护性 | 低 | 高 |
| 多选状态一致性 | 需要手动维护 | 自动处理 |
| 性能影响 | 每次渲染都判断 | 仅在交互时触发 |
实际业务中,行级选择权限往往需要综合多个因素。例如电商后台可能需要同时考虑:
我们可以封装一个权限判断工厂函数:
javascript复制const createSelectable = (auth) => (row) => {
// 状态判断
if (row.status === 'completed') return false
// 角色判断
if (auth.role === 'cs' && row.amount > 10000) return false
// 时间判断
const now = new Date()
if (now > new Date('2023-11-11') && now < new Date('2023-11-12')) {
return auth.role === 'admin'
}
return true
}
// 在组件中使用
export default {
computed: {
selectable() {
return createSelectable(this.$store.getters.auth)
}
}
}
当权限规则需要响应式更新时,可以利用Vue的计算属性特性:
javascript复制export default {
data() {
return {
forceDisableIds: [] // 来自API的不可操作ID列表
}
},
computed: {
selectable() {
return (row) => {
// 响应forceDisableIds的变化
return !this.forceDisableIds.includes(row.id) && row.isActive
}
}
},
async created() {
this.forceDisableIds = await fetchDisabledItems()
}
}
在中大型项目中,建议将所有的selectable逻辑统一管理:
code复制src/
├── utils/
│ └── selectableRules.js
└── components/
└── Table/
└── useSelectable.js
selectableRules.js定义各种业务规则:
javascript复制export const orderSelectable = (auth, row) => {
// 订单业务专用规则
}
export const userSelectable = (auth, row) => {
// 用户管理专用规则
}
useSelectable.js提供组合式API封装:
javascript复制import { orderSelectable } from '@/utils/selectableRules'
export function useOrderSelectable() {
const store = useStore()
const selectable = computed(() =>
(row) => orderSelectable(store.getters.auth, row)
)
return { selectable }
}
开发阶段可以添加调试模式,在控制台输出选择判断的详细信息:
javascript复制selectable(row) {
const result = this.checkSelectable(row)
if (process.env.NODE_ENV === 'development') {
console.table([
{ 行ID: row.id,
状态: row.status,
是否可选: result,
判断规则: 'status !== "completed"'
}
])
}
return result
}
当表格数据量超过1000行时,频繁的selectable调用可能影响性能。可以采用以下优化策略:
javascript复制// 使用记忆函数缓存结果
import memoize from 'lodash/memoize'
export default {
computed: {
selectable() {
return memoize((row) => {
return heavyCheck(row)
}, (row) => row.id) // 以ID作为缓存键
}
}
}
某些情况下需要临时覆盖默认规则,可以通过ref直接操作表格实例:
javascript复制// 临时禁用所有选择
this.$refs.table.clearSelection()
this.$refs.table.toggleAllSelection(false)
// 强制选中某行(即使selectable返回false)
const row = this.tableData[0]
this.$refs.table.toggleRowSelection(row, true)
注意:直接操作表格实例是应急方案,在正规业务逻辑中仍应通过selectable函数控制
表格行级选择权限的控制看似简单,但在复杂的业务系统中,优雅的实现方案能显著提升代码的可维护性和可扩展性。Element UI的selectable属性配合合理的架构设计,可以帮我们构建出既满足业务需求,又保持代码整洁的解决方案。