自定义指令示例:权限控制指令 v-permission
场景说明
实现一个根据用户权限动态控制元素显示/隐藏或禁用操作的指令,支持以下功能:
- 根据权限列表隐藏无权限的元素。
- 可选禁用元素而非隐藏(如按钮变灰)。
- 权限变更时自动更新元素状态。
完整代码与逐行解析
ini
// permissionDirective.js
export default {
// 元素挂载或更新时触发
mounted(el, binding) {
updateElementPermission(el, binding);
},
// 绑定值或参数变化时触发
updated(el, binding) {
updateElementPermission(el, binding);
},
};
// 统一处理权限逻辑
function updateElementPermission(el, binding) {
// 1. 获取必要数据
const { value, modifiers, arg } = binding;
const hasPermission = checkPermission(value); // 核心权限校验
// 2. 处理无权限的情况
if (!hasPermission) {
// 禁用模式(通过参数指定,如 v-permission:disable)
if (arg === 'disable') {
el.disabled = true; // 禁用表单元素
el.style.opacity = '0.5'; // 视觉提示
el.title = '无权限操作'; // 鼠标悬停提示
}
// 默认隐藏模式
else {
el.style.display = 'none'; // 直接隐藏元素
}
}
// 3. 处理有权限的情况(恢复初始状态)
else {
// 禁用模式的恢复
if (arg === 'disable') {
el.disabled = false;
el.style.opacity = '1';
el.title = '';
}
// 隐藏模式的恢复
else {
el.style.display = '';
}
}
// 4. 支持强制显示(通过修饰符,如 v-permission.force)
if (modifiers.force) {
el.style.display = '';
el.disabled = false;
}
}
// 模拟权限校验(实际从 Vuex/Pinia 获取)
function checkPermission(requiredPermission) {
// 实际项目中从全局状态获取用户权限
const userPermissions = ['view', 'edit'];
return userPermissions.includes(requiredPermission);
}
逐行代码解析
1. 指令生命周期处理
scss
export default {
mounted(el, binding) { // 元素挂载时初始化
updateElementPermission(el, binding);
},
updated(el, binding) { // 绑定值变化时更新
updateElementPermission(el, binding);
},
};
-
关键点:
mounted
:元素首次插入 DOM 时校验权限。updated
:当指令绑定的值(如权限要求)或参数变化时重新校验。
**2. 统一处理函数 updateElementPermission
**
javascript
function updateElementPermission(el, binding) {
const { value, modifiers, arg } = binding;
const hasPermission = checkPermission(value);
// ...
}
-
解构赋值:
value
:指令绑定的值,如v-permission="'edit'"
中的'edit'
。modifiers
:修饰符对象,如.force
对应modifiers.force: true
。arg
:指令参数,如:disable
对应arg: 'disable'
。
3. 权限校验逻辑
ini
function checkPermission(requiredPermission) {
const userPermissions = ['view', 'edit'];
return userPermissions.includes(requiredPermission);
}
- 模拟数据:实际项目中需从全局状态(如 Vuex)获取用户权限列表。
- 返回值:当前用户是否拥有所需权限。
4. 无权限处理 - 禁用模式
ini
if (arg === 'disable') {
el.disabled = true; // 适用于按钮、输入框等
el.style.opacity = '0.5'; // 视觉提示
el.title = '无权限操作'; // HTML 原生属性提示
}
-
适用场景:允许用户看到元素但无法交互(如灰色按钮)。
-
细节:
el.disabled
仅对表单元素有效,普通元素需用 CSS 或事件拦截。
5. 无权限处理 - 默认隐藏模式
arduino
else {
el.style.display = 'none'; // 彻底隐藏元素
}
- 优势:完全移除元素对布局的影响。
- 注意 :若元素含动画,可用
visibility: hidden
+opacity: 0
代替。
6. 权限恢复处理
ini
else {
if (arg === 'disable') {
el.disabled = false;
el.style.opacity = '1';
el.title = '';
} else {
el.style.display = '';
}
}
- 恢复逻辑 :重置元素到初始状态,
display: ''
会恢复为 CSS 定义的值。
7. 强制显示模式
ini
if (modifiers.force) {
el.style.display = '';
el.disabled = false;
}
- 用途 :开发阶段临时覆盖权限控制,如
v-permission.force
。 - 扩展性 :可结合环境变量自动启用(如
process.env.NODE_ENV === 'development'
)。
高级使用示例
场景1:禁用无权限的删除按钮
ini
<template>
<button
v-permission:disable="'delete'"
@click="handleDelete"
>删除数据</button>
</template>
- 效果 :用户无
delete
权限时按钮变灰且提示。
场景2:动态切换权限
xml
<template>
<div>
<button @click="togglePermission">切换权限</button>
<p v-permission="requiredPermission">需要{{ requiredPermission }}权限的内容</p>
</div>
</template>
<script>
export default {
data() {
return {
requiredPermission: 'edit'
};
},
methods: {
togglePermission() {
this.requiredPermission = this.requiredPermission === 'edit' ? 'view' : 'edit';
}
}
};
</script>
- 动态响应:点击按钮切换所需权限,指令自动更新元素状态。
对比其他实现方案
方案 | 优点 | 缺点 |
---|---|---|
自定义指令 | 逻辑复用,统一管理 | 需处理全局状态访问 |
组件封装 | 可复用带权限控制的组件 | 每个需控制的组件都要封装 |
v-if + 计算属性 | 简单场景直观 | 重复代码多,难以统一修改逻辑 |
总结
-
核心价值:通过指令集中处理权限逻辑,避免重复代码。
-
扩展性 :通过参数(
:disable
)和修饰符(.force
)支持多样化需求。 -
响应式:利用 Vue 的响应式系统,权限变化时自动更新元素状态。
-
注意事项:
- 普通元素禁用需手动拦截事件(如添加
@click.stop
)。 - 实际项目需接入全局权限状态(如从 Vuex 获取用户权限)。
- 普通元素禁用需手动拦截事件(如添加