Vue3自定义指令封装-按钮权限控制v-permission、hasPermissions

        背景:平常所接触到的系统权限控制,大部分都是菜单、路由级别的控制,但后台管理系统中,很多操作都是与职责和角色挂钩的,同样一个列表,不同人的操作列并不都一样,有些页面存在一些含有重要数据的组件,也会进行相应的权限控制,仅让领导层能看到。

        按钮级权限:根据用户的权限不同,对不同的按钮进行权限控制,对同一组数据,不同的用户是否可以增删改查。对某些用户来说是只读浏览数据,对某些用户来说是可编辑的数据。除了按钮,比如页面中的某个字段,某个div,某个组件要求根据当前用户的权限进行控制时,都可以称为按钮级权限。

     因此,有必要实现按钮/组件级别的权限控制,为了更加方便高效地使用更细粒度的权限控制,封装了一个自定义指令插件v-permission,可实现随时注入使用。

v-permission插件

        一个基于Vue3进行封装的自定义指令,在这个插件中,你可以检查传入的系统权限列表和用户拥有的权限列表,来确定用户是否具有某个组件/按钮级别的权限,实现更细粒度的权限控制。

功能:

① 指令:有权限时显示 UI,无权限时不渲染。避免出现用户看得见按钮,点击却无反应或出现无权限提示,这种不友好的使用体验。

②方法:可用于一些前置处理,比如进入页面时,根据是否有权限来判断默认渲染哪个组件作为该用户能看到的首页。

方式一:封装成可下载的npm包

        在公司中,为了减少重复劳动,防止重复造轮子,开发的这种通用插件是直接传到npm上,再下载到项目中使用的,于是笔者将该插件单独写在一个很简单的小项目中,具体可见:

         该插件的源代码及其使用文档均放在该仓库中。

GitHub - yoguoer/v-permissionContribute to yoguoer/v-permission development by creating an account on GitHub.icon-default.png?t=N7T8https://github.com/yoguoer/v-permission.git

方式二:在项目中直接封装插件

        当然啦,我们也可以直接在项目中去实现这个插件,下面介绍一下操作步骤。

        1. 在根目录下新建一个directive文件夹,用来存放我们自己开发的所有插件。为了便于区分,我们再建一个vPermission文件夹,用来存放我们的v-permission插件。

        2. 在directive/vPermission/permission.ts文件写入以下内容:

/**
* 权限指令
* 使用: v-permission="{module:'模块名称',auth:'权限key值'}"
* const hasPermi = hasPermissions({ module: 'someModule', auth: 'someAuth' });
*/

/**  
  * 初始化全局权限判断方法  
  * permissionList 系统预先配置的权限列表,包含所有权限信息
  * permissions 用户当前权限列表(服务端返回接口权限列表数据) 
 */
export function initHasPermission(options: {
  permissionList: Array<string> | null,
  permissions: Array<string> | null
}
) {
  const { permissionList = null, permissions = null } = options;
  // 返回一个函数,该函数接收一个权限对象并返回是否有权限    
  return (permission: {
    module: string,
    auth: string,
  }) => {
    if (!permissionList || !permissions) {
      throw new Error('permissionList or permissions is null');
    }
    if (permission.module && permission.auth) {
      const value = permissionList[permission.module][permission.auth];
      return permissions.includes(value);
    }
    return false;
  };
}

// 检查权限并执行相应的操作  
function checkPermission(el: any, binding: any, hasPermissions: Function) {
  if (typeof binding.value === 'object' && binding.value.module && binding.value.auth) {
    if (!hasPermissions(binding.value)) {
      el.style.display = 'none';
    } else {
      el.style.display = ''; // 如果有权限,确保元素可见  
    }
  }
}

// 权限指令  
// 创建一个返回指令对象的函数,该函数接受 hasPermissions 函数作为参数  
export default function createPermissionDirective(hasPermissions: Function) {
  return {
    mounted(el: any, binding: any) {
      checkPermission(el, binding, hasPermissions);
    },
    updated(el: any, binding: any) {
      checkPermission(el, binding, hasPermissions);
    }
  };
}

        3. 在directive/vPermission/index.ts文件写入以下内容:

import createPermissionDirective from './permission';
import { initHasPermission } from './permission'

// Vue 3 插件定义   
const install = function (app: any, options: {
  permissionList: Array<string> | null,
  permissions: Array<string> | null
} = {
    /** permissionList 系统预先配置的权限列表,包含所有权限信息
    *   permissions 用户当前权限列表(服务端返回接口权限列表数据) 
    */
    permissionList: null,
    permissions: null
  }) {

  // 初始化权限检查函数 
  const hasPermissions = initHasPermission(options);
  // 添加全局方法 $hasPermissions  
  app.config.globalProperties.$hasPermissions = hasPermissions;


  // 提供全局的权限检查对象 
  app.provide('hasPermissions', app.config.globalProperties.$hasPermissions);

  // 使用 hasPermissions 函数创建指令对象  
  const permissionDirective = createPermissionDirective(hasPermissions);
  // 注册全局指令 v-permission  
  app.directive('permission', permissionDirective);

}

// 导出插件对象  
export default {
  install
};

插件使用方法

  • 在你的项目根目录中新建一个permission文件夹,并在文件夹下新建一个index.ts文件和一个modules文件夹。

modules文件夹用来放置不同模块的权限控制文件(一般各个模块各自建一个.ts文件),而index.ts用来遍历读取modules下的所有文件,并将所有文件转换为键值对的形式,整合成一个包含系统所有权限信息的对象,即:{ 模块名:{ 该模块的权限列表 }, ... }。

  • 在index.ts文件中键入以下代码:
/**
 * 权限配置模块文件,统一引入所有权限配置文件
 */
const files = import.meta.glob('./modules/*.ts');
const modules = {};
for (const path in files) {
  files[path]().then((mod) => {
    let fileNameMatch = path.match(/([^\/\\]+?)\.\w+$/);
    let fileName = fileNameMatch ? fileNameMatch[1] : null;
    modules[fileName as string] = mod?.default
  });
}

export default modules
  • 在modules下新建所需要的模块文件,文件中的内容格式形如以下例子(权限key值: 权限标识):
export default {
    add: '/add-add',
    delete: '/delete-delete', 
    edit: '/edit-edit', 
}
  • 引入index.ts中整理好的系统预先配置的权限列表,作为我们所需要的参数permissionList,。
import permissionList from './permission'
  • 通过接口获取当前用户的权限列表,作为我们所需要的参数permissions。
import permissions from '存放服务端返回接口权限列表数据的地方'

permissionList形如:

{
    "admin": {
        "add": "/admin-add",
        "delete": "/admin-delete",
        "edit": "/admin-edit"
    },
    "user": {
        "add": "/user-add",
        "delete": "/user-delete"
    }
}

permissions形如:

[
    "/user-add",
    "/user-delete"
]
  • 在项目中的入口文件中引入 v-permission,将前面提到的两个参数作为选项,然后使用插件并传入选项:
import { createApp } from 'vue'
import App from './views/App.vue'
import permission from "@/directive/permission" 
import permissionList from '@/permission'
import permissions from '存放服务端返回接口权限列表数据的地方'

const app = createApp(App);

const options = {
    permissionList,
    permissions
}

app.use(permission, options)

app.mount('#app')
  • 在文件中使用。
  • 以指令的方式使用:

    • v-permission指令形式:

      <el-button v-permission="{ module: '模块名', auth: '权限key值' }"> 有权限则显示 </el-button>
      
    • v-if指令形式:

      <el-button v-if="hasPermissions({ module: '模块名', auth: '权限key值' })"> 有权限则显示 </el-button>
      
  • 以方法的方式使用:

    import { inject } from "vue";
    
    // 注入权限判断方法 hasPermissions
    const hasPermissions = inject("hasPermissions");
    if (hasPermissions({ module: '模块名', auth: '权限key值' })) {
      console.log("用户有权限");
    } else {
      console.log("用户没有权限");
    }
    
  • 30
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值