V-Permission 权限验证 Vue2+js权限按钮的实现

1,344 阅读4分钟
第一次写文章,如有错误,请您提出来,我万分感谢,虚心接受。如果有不懂的,请评论区提问!谢谢!!

首先这篇文章不适合没有学习完vue2基础的小伙伴!学习完vue2还没进行项目编写的小伙伴!

我是一个前端半年小白,公司项目更新添加了权限验证。以下是我实现权限按钮的几个步骤:

一、获取权限数据(这个地方主要是我封装axios的笔记,方便我个人回来观看,想了解V-Permission的小伙伴可以向下滑去看)

  • 简单概括一下:通过点击”登录按钮“,触发一个axios来完成的ajax请求。通过请求来获取权限的数据。

截屏2023-02-03 下午4.16.42.png 网络窗口下,左边灰色标记内的是接口名,右边预览窗口中的内容是权限数据。

二、使用Vux将获取的权限数据通过vuex实现组件全局状态管理。

Vuex是干什么的呢?是实现组件全局状态(数据)管理的一种机制,可以方便的实现组件之间数据的共享。 Vuex的四个核心概念: State、Mutation、Action、Getter

State:提供唯一的公共数据资源,所有的共享数据都要统一的放到Store的state中进行存储。

Mutation: 用于修改state中的数据。

Action : 一般用来搞一些异步任务触发行为。

Getter: Getter可以对Store中已有的数据加工处理之后形成新的数据,类似Vue的计算属性。 Store中数据发生变化,Getter的数据也会跟着变化 。

关于Vuex详细的相关介绍,建议观看哔哩哔哩的黑马程序员的Vuex 有些博主都给截出来了也就两个小时左右,你就能了解。 黑马程序员Vuex:哔哩哔哩网址

随着版本的升级 pinia也随着广泛的被应用。pinia也是一种全局数据状态管理。比较vuex简单。

我是在登录点击按钮下添加了一个权限请求接口,然后再调用Vuex的action中的函数。

  permissions({  //这是一个封装好的接口方法用来申请权限数据的 
    canedittable: '',
    roleid: 1       //canedittable与roleid 接口需要传的参数。
  }).then((res) => {
    this.$store.dispatch("user/loginPermission",res)
    // 这里就是使用到的Vuex。 通过dispatch函数来触发。 dispatch函数中第一个参数是Action中的定义的函数,第二个参数,是我们传递的参数。
  }).catch((error) => {
    console.log(error)
  })
  

Vuex store中的action中的loginPermission函数,调用mutation中的SET_PERMISSIONS函数 (mutation 只能通过mutations对state进行修改),这个地方我对接受的参数进行了格式转换,因为这个项目不是一个人编写的,经过好几个人的手,所以我将格式转换成我习惯的用法。

loginPermission({ commit }, res) {  //这地方通过调用了mutations 中的SET_PERMISSIONS 方法

commit("SET_PERMISSIONS", res)

Cookies.set("USER_PERMISSIONS", state.perms) },


action中的SET_PERMISSIONS

SET_PERMISSIONS: (state, res) => {  //这个地方我是将数据进行了格式转换
   for (const key in res) {
   for (const value of res[key]) {
    state.perms.push(key + ":" + value)
    }
   }
  }

getter的使用

const getters = {
language: state => state.app.language,
device: state => state.app.device,
sidebar: state => state.app.sidebar,
showSet: state => state.app.showSet,
routes: state => state.user.routes,
perms:state=>state.user.perms, //这里我主要是添加了这个参数  
singleRoutes: state => state.user.singleRoutes,
activeRoute: state => state.user.activeRoute,
skinChoose: state => state.settings.skinChoose,
}
export default getters

store封装

截屏2023-02-06 上午9.18.37.png index中的代码

import { createStore } from "vuex";
import createPersistedState from "vuex-persistedstate";
import getters from "./getters";
const modulesFiles = import.meta.globEager("./modules/*.js");
const modules = Object.keys(modulesFiles).reduce((modules, modulePath) => {
const moduleName = modulePath.replace(/(.*\/)*([^.]+).*/gi, "$2"); //正则表达是获取模块名称,也就是文件名称
const value = modulesFiles[modulePath];
modules[moduleName] = value.default;
return modules;
}, {});
const store = createStore({
modules,
getters,
plugins: [createPersistedState({})] //这个是一个插件,方便vuex中的数据进行本地存储。
});

export default store;

这里面用到了vuex-persistedstate插件,当然你也可以不用,但是你需要对state中的数据做本地存储,用的时候还要进行解析,但是使用了这个组件就不需要进行解析跟存储,它会自动给你进行本地存储,进行解析。详细介绍请看掘金找到Web

三、V-Permission的创建

1、创建permission.js

import store from '@/store'
function checkPermission(el, binding) {
// 这里的el指的是我们封装的组件
// building是权限名称
const { value } = binding
// value是一个数组
const roles = store.getters && store.getters.perms  //roles  把store中的 state中     perms给了roles
// roles是vuex中state中的perms数组
if (value && value instanceof Array) {
if (value.length > 0) {
  const permissionRoles = value
  const hasPermission = roles.some(role => {
    return permissionRoles.includes(role)  //这里用到了js数组中的include方法 返回的结果是一个布尔类型。
  })
  if (!hasPermission) {  //如果没有hasPermission 组件就不显示
    el.parentNode && el.parentNode.removeChild(el)
  }
}
} else {
throw new Error(`need roles! Like v-permission="['admin','editor']"`)
 }
}

export default {
 mounted(el, binding) {
// 这个地方在使用的时候  切记使用的是mounted而不是inserted
// 我看过一个文件它使用的就是inserted,结果就是没有任何反应
checkPermission(el, binding)
 },
update(el, binding) {
 checkPermission(el, binding)
 }
}

2、封装v-permission指令(index.js与permission.js同级)

import permission from './permission'
//这里封装了一个新的vue指令 v-permission
// 这里需要在main.js中进行使用
const install = function(Vue) {
Vue.directive('permission', permission)
 }
if (window.Vue) {
window['permission'] = permission
Vue.use(install); // eslint-disable-line
}
permission.install = install
export default permission

3、在main.js中使用permission

 import permission from "./directive/permission/index"//这里我们引用的是index.js文件而不是permission.js文件
 app.use(permission)
 

四、封装组件(brisk-button.vue) 封装的时候,我使用的是element ui 我里面有两个传递参数,一个是content,一个是v-permission指令中的permission。

为了方便减少代码量这里我将点击事件的方法也给写在了封装的组件中. 这里有个问题好像我们在封装的组件里没有给他添加点击事件,而是在组件外部添加点击事件的话好像触发不了。

<template>
    <el-tooltip class="item" effect="dark" :content="content">
    
        <el-icon :size="20" :color="'#ca4341'" class="table-new-button" v-permission="[permission]" @click="handleClick"
           >
            <Delete />
        </el-icon>
    </el-tooltip>
</template>

 <script>
export default {
name: 'brisk-delete',
data() {
    return {
    }
},
props: {
    content: {
        type: String,
        default: "删除"
    },
    permission: {
        type: String,
        default: undefined
    }
},
mounted() {
    console.log(this.permission);
},
methods: {
    handleClick() {
        const
            message = "此操作将永久删除该文件, 是否继续?",
            title = "提示",
            confirmButtonText = "确定",
            cancelButtonText = "取消",
            type = "waring"
        this.$confirm(message, title, {
            confirmButtonText,
            cancelButtonText
        }).then((res) => {
            this.$message({
                message: '删除成功',
                type: 'success',
            })
                .catch(() => {
                    this.$message({
                        type: 'info',
                        message: '已取消删除'
                    });
                });
        })
    }
},
}
</script>
<style lang="scss" scoped>

 .table-new-button{
cursor: pointer;
}
</style>

五、封装组件的使用 使用的时候我们需要提供两个参数,一个是content,一个是perimission。也就是数据权限。

第一步引入组件

 import  BriskButton from  '../../components/crud/brisk-delete.vue'
 
 export default {   //这个地方代码不全,只是给大家代码提示。
 name: 'teachlog',
 components: {
    BriskButton  //这里一定要有
},
directives: {

},

第二步 使用添加参数

     <brisk-button :content="content"  permission='AbsenceInfoColumns:Details'> </brisk-button>

六、效果

正常运行 截屏2023-02-06 上午9.53.47.png

给一个这个用户没有的权限

截屏2023-02-06 上午9.55.28.png

结果

截屏2023-02-06 上午9.56.57.png

七、小总结

全局状态的数据必须进行存储,可以是本地存储,也可以是会话存储。 当然也可以使用上面提到过的vue-createPersistedState插件进行存储,这种方式更高效一点。