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. 验证步骤

  1. 检查控制台:确保无 Failed to resolve directive 警告
  2. 模拟权限数据:在 userStore 中修改 ruleNames 观察元素是否隐藏/禁用
  3. UI测试:无权限时按钮应显示为灰色且不可点击,有权限时正常显示

7. 注意事项

  • 数据响应性:若权限数据动态变化,需在指令中监听 userStore 的更新
  • 组件移除 vs 禁用el.parentNode.removeChild(el) 会直接移除元素,建议优先禁用并保留视觉反馈
  • 样式增强:可通过CSS类实现更丰富的权限提示样式

通过以上步骤,可实现细粒度的权限控制,并确保代码模块化、可维护性高。

最后修改:2025 年 04 月 24 日
如果觉得我的文章对你有用,请随意赞赏