使用vue3自定义指令搞定前端权限

1. 参考vue3 官方问自定义指令。

site: 自定义指令 | Vue.js

2. 大概步骤分2步。

  1. 写指令
  2. 发布(安装)指令。

3. 具体代码如下:

import type { Directive, DirectiveBinding } from 'vue'
import { useUserStore } from '@/stores/user'

/**
 * 权限指令
 * 用法: v-permission="'system:admin:create'" 或 v-permission="['system:admin:create', 'system:admin:update']"
 * 模式: v-permission:hide="'system:admin:create'" (隐藏元素)
 * 模式: v-permission:disable="'system:admin:create'" (禁用元素)
 */
export const permission: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    checkPermission(el, binding)
  },
  updated(el: HTMLElement, binding: DirectiveBinding) {
    checkPermission(el, binding)
  }
}

/**
 * 角色指令
 * 用法: v-role="'admin'" 或 v-role="['admin', 'super_admin']"
 * 模式: v-role:hide="'admin'" (隐藏元素)
 * 模式: v-role:disable="'admin'" (禁用元素)
 */
export const role: Directive = {
  mounted(el: HTMLElement, binding: DirectiveBinding) {
    checkRole(el, binding)
  },
  updated(el: HTMLElement, binding: DirectiveBinding) {
    checkRole(el, binding)
  }
}

/**
 * 检查权限
 */
function checkPermission(el: HTMLElement, binding: DirectiveBinding) {
  const { value, modifiers } = binding
  const userStore = useUserStore()

  if (!value) {
    console.warn('v-permission directive requires a permission value')
    return
  }

  // admin账户拥有所有权限,直接跳过检查
  if (userStore.isAdmin) {
    // 确保元素是可见和可用的
    if (modifiers.hide) {
      el.style.display = ''
    } else if (modifiers.disable) {
      el.removeAttribute('disabled')
      el.style.opacity = ''
      el.style.cursor = ''
      el.style.pointerEvents = ''
    }
    return
  }

  // 权限值可以是字符串或数组
  const permissions = Array.isArray(value) ? value : [value]
  const hasPermission = permissions.some(permission => userStore.hasPermission(permission))

  if (!hasPermission) {
    if (modifiers.hide) {
      // 隐藏模式:直接隐藏元素
      el.style.display = 'none'
    } else if (modifiers.disable) {
      // 禁用模式:禁用元素
      el.setAttribute('disabled', 'disabled')
      el.style.opacity = '0.5'
      el.style.cursor = 'not-allowed'
      el.style.pointerEvents = 'none'
    } else {
      // 默认模式:移除元素
      el.remove()
    }
  } else {
    // 有权限时,确保元素是可见和可用的
    if (modifiers.hide) {
      el.style.display = ''
    } else if (modifiers.disable) {
      el.removeAttribute('disabled')
      el.style.opacity = ''
      el.style.cursor = ''
      el.style.pointerEvents = ''
    }
  }
}

/**
 * 检查角色
 */
function checkRole(el: HTMLElement, binding: DirectiveBinding) {
  const { value, modifiers } = binding
  const userStore = useUserStore()

  if (!value) {
    console.warn('v-role directive requires a role value')
    return
  }

  // admin账户拥有所有角色权限,直接跳过检查
  if (userStore.isAdmin) {
    // 确保元素是可见和可用的
    if (modifiers.hide) {
      el.style.display = ''
    } else if (modifiers.disable) {
      el.removeAttribute('disabled')
      el.style.opacity = ''
      el.style.cursor = ''
      el.style.pointerEvents = ''
    }
    return
  }

  // 角色值可以是字符串或数组
  const roles = Array.isArray(value) ? value : [value]
  const hasRole = roles.some(role => userStore.hasRole(role))

  if (!hasRole) {
    if (modifiers.hide) {
      // 隐藏模式:直接隐藏元素
      el.style.display = 'none'
    } else if (modifiers.disable) {
      // 禁用模式:禁用元素
      el.setAttribute('disabled', 'disabled')
      el.style.opacity = '0.5'
      el.style.cursor = 'not-allowed'
      el.style.pointerEvents = 'none'
    } else {
      // 默认模式:移除元素
      el.remove()
    }
  } else {
    // 有角色时,确保元素是可见和可用的
    if (modifiers.hide) {
      el.style.display = ''
    } else if (modifiers.disable) {
      el.removeAttribute('disabled')
      el.style.opacity = ''
      el.style.cursor = ''
      el.style.pointerEvents = ''
    }
  }
}

/**
 * 权限检查函数(用于组合式API)
 */
export function usePermission() {
  const userStore = useUserStore()

  const hasPermission = (permissions: string | string[]) => {
    const permissionList = Array.isArray(permissions) ? permissions : [permissions]
    return permissionList.some(permission => userStore.hasPermission(permission))
  }

  const hasRole = (roles: string | string[]) => {
    const roleList = Array.isArray(roles) ? roles : [roles]
    return roleList.some(role => userStore.hasRole(role))
  }

  const hasAnyPermission = (permissions: string[]) => {
    return permissions.some(permission => userStore.hasPermission(permission))
  }

  const hasAllPermissions = (permissions: string[]) => {
    return permissions.every(permission => userStore.hasPermission(permission))
  }

  const hasAnyRole = (roles: string[]) => {
    return roles.some(role => userStore.hasRole(role))
  }

  const hasAllRoles = (roles: string[]) => {
    return roles.every(role => userStore.hasRole(role))
  }

  return {
    hasPermission,
    hasRole,
    hasAnyPermission,
    hasAllPermissions,
    hasAnyRole,
    hasAllRoles
  }
}

/**
 * 安装权限指令
 */
export function setupPermissionDirectives(app: any) {
  app.directive('permission', permission)
  app.directive('role', role)
}

/**
 * 导出所有指令
 */
export default {
  permission,
  role
} 

4. 具体请参考: 

https://github.com/scoutchloe/nextera-framework/tree/master/management/frontend/src/directives

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值