昨天我们讲解了vue3自定义指令

这里可以先定义2个实现前端按钮级别权限的实现。

v-hasPermi, v-hasRole这2个指令,来实现是否有对应的权限。

一、自定义指令实现前端按钮级别权限

首先在@/src/directive这个目录下新建index.js,然后新建permission文件夹,在permission文件夹下新建2个文件,

一个是haspermi.js,一个是hasrole.js。

directive目录下用于项目存放自定义指令。这个目录下的index.js主要是用于注册这些指令的,在main.js中引入他直接全部注册,不用在main.js中单独写一个一个注册。


hasPermi.js

/**
 * v-hasPermi 操作权限处理
 * Copyright (c) 2019 ruoyi
 */
 
import useUserStore from '@/stores/user'

export default {
  mounted(el, binding, vnode) {
    const { value } = binding
    const all_permission = "*:*:*";
    const permissions = useUserStore().permissions

    if (value && value instanceof Array && value.length > 0) {
      const permissionFlag = value

      const hasPermissions = permissions.some(permission => {
        return all_permission === permission || permissionFlag.includes(permission)
      })

      if (!hasPermissions) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error(`请设置操作权限标签值`)
    }
  }
}


hasRole.js

/**
 * v-hasRole 角色权限处理
 * Copyright (c) 2019 ruoyi
 */
 
import useUserStore from '@/stores/user'

export default {
  mounted(el, binding, vnode) {
    const { value } = binding
    const super_admin = "admin";
    const roles = useUserStore().roles

    if (value && value instanceof Array && value.length > 0) {
      const roleFlag = value

      const hasRole = roles.some(role => {
        return super_admin === role || roleFlag.includes(role)
      })

      if (!hasRole) {
        el.parentNode && el.parentNode.removeChild(el)
      }
    } else {
      throw new Error(`请设置角色权限标签值`)
    }
  }
}


directive目录下的index.js

import hasRole from './permission/hasRole'
import hasPermi from './permission/hasPermi'
import copyText from './common/copyText'

export default function directive(app){
  app.directive('hasRole', hasRole)
  app.directive('hasPermi', hasPermi)
  app.directive('copyText', copyText)
}


在项目的main.js注册全部指令

// 注册指令,24行48行。
import directive from './directive' 

directive(app);

下面是完整的main.js文件

import { createApp } from 'vue'
import App from './App.vue'
import Cookies from 'js-cookie'


import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
import locale from 'element-plus/es/locale/lang/zh-cn'
import * as ElIcons from '@element-plus/icons-vue'
import Print from 'vue3-print-nb';

import '@/assets/styles/index.scss' // global css

import pinia from './stores'
import router from './router'


// svg图标
import 'virtual:svg-icons-register'
import SvgIcon from '@/components/SvgIcon'

// 注册指令
import plugins from './plugins' // plugins
import directive from './directive' 

import './permission' // permission control

import { useDict } from '@/utils/dict'
import { parseTime, addDateRange, handleTree, resetForm } from '@/utils/ruoyi'


//require('./mock');
const app = createApp(App)
console.log(app.config);
console.log(import.meta.env.VITE_APP_BASE_API, '环境')
// 全局方法挂载
app.config.globalProperties.useDict = useDict;
app.config.globalProperties.parseTime = parseTime;
app.config.globalProperties.resetForm = resetForm;
app.config.globalProperties.addDateRange = addDateRange;
app.config.globalProperties.handleTree = handleTree;

app.use(router)
app.use(pinia)
app.use(Print);
app.use(plugins)

directive(app)

for (const name in ElIcons){
	app.component(name, ElIcons[name]);
}
app.component('svg-icon', SvgIcon);

// 使用element-plus 并且设置全局的大小
app.use(ElementPlus, {
    locale: locale,
    // 支持 large、default、small
    size: Cookies.get('size') || 'default'
})
app.mount('#app');


前端页面上使用案例

使用权限字符串 v-hasPermi

// 单个
<el-button v-hasPermi="['system:user:add']">存在权限字符串才能看到</el-button>
// 多个
<el-button v-hasPermi="['system:user:add', 'system:user:edit']">包含权限字符串才能看到</el-button>

使用角色字符串 v-hasRole

// 单个
<el-button v-hasRole="['admin']">管理员才能看到</el-button>
// 多个
<el-button v-hasRole="['role1', 'role2']">包含角色才能看到</el-button>

提示(这个可以不用,如果使用则需要utils下的permisson.js文件)

在某些情况下,它是不适合使用v-hasPermi,如元素标签组件,只能通过手动设置v-if。 可以使用全局权限判断函数,用法和指令 v-hasPermi 类似。

<template>
  <el-tabs>
    <el-tab-pane v-if="checkPermi(['system:user:add'])" label="用户管理" name="user">用户管理</el-tab-pane>
    <el-tab-pane v-if="checkPermi(['system:user:add', 'system:user:edit'])" label="参数管理" name="menu">参数管理</el-tab-pane>
    <el-tab-pane v-if="checkRole(['admin'])" label="角色管理" name="role">角色管理</el-tab-pane>
    <el-tab-pane v-if="checkRole(['admin','common'])" label="定时任务" name="job">定时任务</el-tab-pane>
   </el-tabs>
</template>

<script>
import { checkPermi, checkRole } from "@/utils/permission"; // 权限判断函数

export default{
   methods: {
    checkPermi,
    checkRole
  }
}
</script>


三、这个是utils目录下的permission.js文件(可以不用)

permission.js

import useUserStore from '@/stores/user'

/**
 * 字符权限校验
 * @param {Array} value 校验值
 * @returns {Boolean}
 */
export function checkPermi(value) {
  if (value && value instanceof Array && value.length > 0) {
    const permissions = useUserStore.permissions
    const permissionDatas = value
    const all_permission = "*:*:*";

    const hasPermission = permissions.some(permission => {
      return all_permission === permission || permissionDatas.includes(permission)
    })

    return hasPermission;

  } else {
    console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
    return false
  }
}

/**
 * 角色权限校验
 * @param {Array} value 校验值
 * @returns {Boolean}
 */
export function checkRole(value) {
  if (value && value instanceof Array && value.length > 0) {
    const roles = useUserStore.roles
    const permissionRoles = value
    const super_admin = "admin";

    const hasRole = roles.some(role => {
      return super_admin === role || permissionRoles.includes(role)
    })

    return hasRole;

  } else {
    console.error(`need roles! Like checkRole="['admin','editor']"`)
    return false
  }
}