1. 指令设计目标
通过自定义指令 v-permission
实现按钮/组件级权限控制,根据用户权限动态展示或隐藏元素。
2. 完整实现步骤
(1) 创建权限指令文件
在 src/directives/permission.ts
中定义指令逻辑:
// src/directives/permission.ts
import { Directive, DirectiveBinding } from 'vue';
import { useUserStore } from '@/stores/user'; // 引入用户状态管理
export const permissionDirective: Directive = {
mounted(el: HTMLElement, binding: DirectiveBinding) {
const permission = binding.value as string; // 获取指令参数(如 'sys:order:list')
const hasPermission = checkPermission(permission); // 权限检查
if (!hasPermission) {
// 无权限时禁用元素并添加提示
el.disabled = true;
el.title = `需要权限:${permission}`;
el.style.opacity = '0.6';
el.style.pointerEvents = 'none';
}
},
updated(el: HTMLElement, binding: DirectiveBinding) {
this.mounted(el, binding); // 更新时重新检查权限
}
};
// 权限检查函数
function checkPermission(permission: string): boolean {
const userStore = useUserStore();
return userStore.ruleNames.includes(permission); // 根据实际数据字段调整
}
(2) 全局注册指令
在 src/main.ts
中导入并注册指令:
// src/main.ts
import { createApp } from 'vue';
import App from './App.vue';
import { permissionDirective } from './directives/permission'; // 注意拼写
const app = createApp(App);
// 全局注册权限指令
app.directive('permission', permissionDirective); // 名称需与v-xxx一致
app.mount('#app');
(3) 组件中使用指令
在 src/views/index.vue
中应用指令:
<template>
<el-row :gutter="20" class="mt-4">
<el-col :span="12">
<!-- 需要权限 'sys:order:list' 才能显示 -->
<IndexEcharts
v-permission="'sys:order:list'"
ref="orderEcharts"
/>
</el-col>
<!-- 其他代码保持不变 -->
</el-row>
</template>
(4) 用户权限数据管理
确保用户权限数据通过状态管理(如Pinia)存储:
// src/stores/user.ts
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
ruleNames: ['sys:user:list', 'sys:order:list'] // 用户权限列表
}),
// 其他逻辑...
});
3. 关键代码修正说明
(1) 指令名称一致性
- 指令定义:
permissionDirective
- 全局注册:
app.directive('permission', permissionDirective)
- 模板使用:
v-permission="'sys:order:list'"
4. 扩展功能示例
(1) 支持多权限校验
// 在 permission.ts 的 checkPermission 中
if (Array.isArray(binding.value)) {
return binding.value.every(p => checkPermission(p));
} else {
return checkPermission(binding.value);
}
(2) 修饰符支持
// 在 permissionDirective 中
if (binding.modifiers.admin) {
return checkPermission('admin') && checkPermission(binding.value);
}
5. 完整代码结构
src/
├── directives/
│ └── permission.ts
├── stores/
│ └── user.ts
├── views/
│ └── index.vue
├── main.ts
└── ...
6. 验证步骤
- 检查控制台:确保无
Failed to resolve directive
警告 - 模拟权限数据:在
userStore
中修改ruleNames
观察元素是否隐藏/禁用 - UI测试:无权限时按钮应显示为灰色且不可点击,有权限时正常显示
7. 注意事项
- 数据响应性:若权限数据动态变化,需在指令中监听
userStore
的更新 - 组件移除 vs 禁用:
el.parentNode.removeChild(el)
会直接移除元素,建议优先禁用并保留视觉反馈 - 样式增强:可通过CSS类实现更丰富的权限提示样式
通过以上步骤,可实现细粒度的权限控制,并确保代码模块化、可维护性高。