vue自定义“权限控制”指令

16 阅读3分钟

自定义指令示例:权限控制指令 v-permission

场景说明

实现一个根据用户权限动态控制元素显示/隐藏或禁用操作的指令,支持以下功能:

  1. 根据权限列表隐藏无权限的元素。
  2. 可选禁用元素而非隐藏(如按钮变灰)。
  3. 权限变更时自动更新元素状态。

完整代码与逐行解析

// 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. 指令生命周期处理

export default {
  mounted(el, binding) { // 元素挂载时初始化
    updateElementPermission(el, binding);
  },
  updated(el, binding) { // 绑定值变化时更新
    updateElementPermission(el, binding);
  },
};
  • 关键点‌:

    • mounted:元素首次插入 DOM 时校验权限。
    • updated:当指令绑定的值(如权限要求)或参数变化时重新校验。

‌**2. 统一处理函数 updateElementPermission**‌

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. 权限校验逻辑

function checkPermission(requiredPermission) {
  const userPermissions = ['view', 'edit'];
  return userPermissions.includes(requiredPermission);
}
  • 模拟数据‌:实际项目中需从全局状态(如 Vuex)获取用户权限列表。
  • 返回值‌:当前用户是否拥有所需权限。

4. 无权限处理 - 禁用模式

if (arg === 'disable') {
  el.disabled = true; // 适用于按钮、输入框等
  el.style.opacity = '0.5'; // 视觉提示
  el.title = '无权限操作'; // HTML 原生属性提示
}
  • 适用场景‌:允许用户看到元素但无法交互(如灰色按钮)。

  • 细节‌:

    • el.disabled 仅对表单元素有效,普通元素需用 CSS 或事件拦截。

5. 无权限处理 - 默认隐藏模式

else {
  el.style.display = 'none'; // 彻底隐藏元素
}
  • 优势‌:完全移除元素对布局的影响。
  • 注意‌:若元素含动画,可用 visibility: hidden + opacity: 0 代替。

6. 权限恢复处理

else {
  if (arg === 'disable') {
    el.disabled = false;
    el.style.opacity = '1';
    el.title = '';
  } else {
    el.style.display = '';
  }
}
  • 恢复逻辑‌:重置元素到初始状态,display: '' 会恢复为 CSS 定义的值。

7. 强制显示模式

if (modifiers.force) {
  el.style.display = '';
  el.disabled = false;
}
  • 用途‌:开发阶段临时覆盖权限控制,如 v-permission.force
  • 扩展性‌:可结合环境变量自动启用(如 process.env.NODE_ENV === 'development')。

高级使用示例

场景1:禁用无权限的删除按钮

<template>
  <button 
    v-permission:disable="'delete'"
    @click="handleDelete"
  >删除数据</button>
</template>
  • 效果‌:用户无 delete 权限时按钮变灰且提示。

场景2:动态切换权限

<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 获取用户权限)。