vue权限按钮的实现

鉴权函数

由于下面几种方式都需要用到鉴权函数,所以将其放置在组件外面,供组件或其他文件调用。

// src/utils/hasPermission.jsimport { usePermissionStore } from '@/stores'
import array from 'lodash/array'
export const hasPermission = (value, def = true) => {// 不传值,默认视为有权限,不做鉴权if (!value) {return def}const allCodeList = usePermissionStore().getPermCodeList// 如果不是数组,直接判断pinia里的权限数组有没有相同的元素即可if (!Array.isArray(value)) {return allCodeList.includes(value)}// intersection是lodash提供的一个方法,用于返回一个所有给定数组都存在的元素组成的数组return array.intersection(value, allCodeList).length > 0
}

将可以操作按钮的权限码们以权限码数组的形式存放到了pinia中,所以要先获取pinia中的权限数组再进行判断。

  1. 情况一:没有传值,则无法做权限码的比对,所以可以认为不需要鉴权,返回true即可。
  2. 情况二:传入的值是权限码数值,不是数组,那么可以拿pinia中的权限码数组来检测是否包含该权限码,如果有则认为有权限返回true;否则返回false。
  3. 情况三:传入的值是权限码数组,此时需要拿传入的数组和pinia中的权限码数组进行比较,看看是否存在交集,如果有交集则说明有权限,返回true;否则返回false。

Pinia:

// store/index.jsimport { createPinia } from "pinia";const pinia=createPinia()export default piniaexport  * from './modules/permission.js'
// store/modules/permission.jsimport { defineStore } from 'pinia'
import { getPermissionList } from '@/api/permission'
export const usePermissionStore = defineStore('permission', {state: () => ({// 权限代码列表permCodeList: [101, 102, 778, 779]}),getters: {// 获取getPermCodeList() {return this.permCodeList}},actions: {// 存储setPermCodeList(codeList) {this.permCodeList = codeList},// 请求权限码async getPermissionCode() {const codeList = await getPermissionList()this.setPermCodeList(codeList)}}
})

方式一:v-if搭配鉴权函数实现权限按钮

引入鉴权函数,将该能够操作该按钮的权限码以实参形式传入鉴权函数,v-if根据返回值决定是否加载该按钮结构。

<template><div><button class="fun-btn" v-if="hasPermission([101])">你能看到我?-v-if函数实现</button></div>
</template><script setup>
import { hasPermission } from '@/utils/hasPermission'
</script><style scoped lang="scss"></style>

方式二:组件+插槽 实现权限按钮

将按钮以插槽形式放入组件中,给组件以props传递权限码数据,组件中使用鉴权函数来判断传入的权限码是否符合条件,符合则渲染插槽中的结构(按钮),否则不渲染。

<!--components/PermisBtnComp.vue-->
<template></template><script>
// h函数  https://cn.vuejs.org/api/render-function.html#h
// defineComponent-函数签名 https://cn.vuejs.org/api/general.html#definecomponent
import { hasPermission } from '@/utils/hasPermission'
import { renderSlot, h, defineComponent } from 'vue'export default defineComponent({props: {value: {type: [Number, String, Array],default: ''}},setup(props, { slots }) {return () => {// 根据权限判断结果来确定是否要渲染默认插槽的结构// 在 Vue 3 中,通过 renderSlot(父组件传入的插槽内容,插槽名) 函数进行插槽渲染时,需要将其导入并包含在组件的 setup 方法中。// 父组件引用子组件时,子组件标签内的默认内容对应的是:renderSlot(slots, 'default')// return hasPermission(props.value) ? h('div', renderSlot(slots, 'default')) : null// 免去renderSlot https://cn.vuejs.org/guide/extras/render-function.html#rendering-slotsreturn hasPermission(props.value) ? h('div', slots.default()) : null}}
})
</script><style scoped lang="scss"></style>

方式三:自定义指令 实现权限按钮

自定义指令其实和第一种很像,就是我们自己出一个"v-if",只不过是专门用来做权限判断的指令。指令传入的数据即为权限码,指令内部根据指令绑定的数据来做鉴权判断。

注意点1:这里的mounted可能较容易实现,但需要注意updated的设计,考虑到有动态修改指令后面的权限码的可能,所以当涉及到指令后面的权限码修改后,要重新做鉴权判断。

注意点2:自定义指令在内部的鉴权判断后,如果不符合条件要移除指令所在的结构;如果符合条件的话,要把之前因为不符合条件被移除的结构要添加回来,也就是回添操作;回添操作为了避免不知道把原来的结构添加回来到哪个位置,这里使用了document.createComment() 即注释先做占位,等需要回添时使用replaceChild() 把注释替换为按钮结构。如果使用的是remove()removeChild()可能再放回来就不知道放到哪个位置了。

// src/directs/judge-permission.jsimport { hasPermission } from '@/utils/hasPermission'// removeDom、addDom的存在是为了保证自定义指令绑定的权限码数据变化后可以不刷新页面动态添加/移除自定义指令所在的dom节点
// 移除dom节点
const removeDom = (el) => {// 把注释点绑在元素上,方便后面使用el._placeholderNode = document.createComment('permission-btn')// 和父节点关联上,方便后面使用el._parentNode = el.parentNode// 父节点做子元素替换el.parentNode.replaceChild(el._placeholderNode, el)
}// 把移除的dom节点添加回来
const addDom = (el) => {el._parentNode?.replaceChild(el, el._placeholderNode)
}const mounted = (el, binding) => {const permisList = binding.valueif (!permisList) returnif (!hasPermission(permisList)) {// 移除当前dom节点// el.parentNode?.removeChild(el) // 通过父节点删除子自己// el.remove() // 自杀/* 权限值会变,那就涉及到更新后要不要将移除的dom节点添加回来为了能够知道添加回来的dom节点放到哪个地方,可以创建注释节点来占位在添加时只对那个位置的子元素做替换操作即可*/removeDom(el)}
}const updated = (el, binding) => {// 比对前后变化的值,相同不需要后续操作let valDiff = binding.value === binding.oldValueif (valDiff) return// 重新判断改值前后的权限变化,相同不需要后续操作(如:修改前就没权限,修改后依旧没权限,无需操作)let oldPermisStatus = hasPermission(binding.oldValue)let nowPermisStatus = hasPermission(binding.value)if (oldPermisStatus == nowPermisStatus) returnif (nowPermisStatus) {addDom(el)} else {removeDom(el)}
}export const permisDirect = {mounted,updated
}

main.js中添加指令:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import pinia from './stores'
import {permisDirect} from '@/directs/judge-permission'const app=createApp(App)
app.use(pinia)
app.directive('permis',permisDirect)
app.mount('#app')

根组件效果展示

<script setup>
import PermisBtnFun from './components/PermisBtnFun.vue'
import PermisBtnComp from './components/PermisBtnComp.vue'
import { ref } from 'vue'const permis = ref(102)
const permisToggle = () => {// 由于@/utils/hasPermission中有判断!value则返回true,表示没传值默认不需要鉴权,返回true放行// 所以这里在调整权限值的时候不能改成0,因为!0==true,如果变化前就有权限(true),变化后想没权限改为0,刚好!0是true,弄巧成拙,依旧显示。permis.value === 102 ? (permis.value = 100) : (permis.value = 102)
}
</script><template><div class="btns-container"><!-- v-if搭配函数方式 --><PermisBtnFun /><!-- 组件+插槽方式 --><PermisBtnComp :value="101"><button class="comp-slot-btn">就你能耐?-组件插槽实现</button></PermisBtnComp><!-- 自定义指令方式 --><button class="vpermis-btn" v-permis="permis">你依旧能看得到我?-自定义指令实现</button><!-- 修改自定义指令绑定的权限值,测试自定义指令updated中的移除和回添的操作 --><button @click="permisToggle">修改自定义指令绑定的权限值</button></div>
</template><style scoped>
.btns-container {display: flex;flex-direction: column;justify-content: space-around;height: 400px;
}
/* ::v-deep usage as a combinator has been deprecated. Use :deep(<inner-selector>) instead. */
:deep(.fun-btn) {background-color: #acd384;color: #fff;
}
.vpermis-btn {background-color: #f38585;color: #fff;
}
.comp-slot-btn {background-color: #5aa3f8;color: #fff;
}
</style>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/12092.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

EXCEL,如何比较2个表里的数据差异(使用数据透视表)

目录 1 问题: 需要比较如下2个表的内容差异 1.1 原始数据喝问题 1.2 提前总结 2 使用EXCEL公式方法 2.1 新增辅助列&#xff1a; 辅助index 2.2 具体公式 配合条件格式 使用 3 数据透视表方法 3.1 新增辅助列&#xff1a; 辅助index 3.2 需要先打开 数据透视表向导 …

Ubuntu 20.04 Ubuntu18.04安装录屏软件Kazam

1.在Ubuntu Software里面输入Kazam&#xff0c;就可以找不到这个软件&#xff0c;直接点击install就可以了 2.使用方法&#xff1a; 选择Screencast&#xff08;录屏&#xff09; Fullscreen&#xff08;全屏&#xff09;-----Windows&#xff08;窗口&#xff09;--------Ar…

20.3 HTML表格

1. table表格 table标签是HTML中用来创建表格的元素. table标签通常包含以下子标签: - th标签: 表示表格的表头单元格(table header), 用于描述列的标题. - tr标签: 表示表格的行(table row). - td标签: 表示表格的单元格(table data), 通常位于tr标签内, 用于放置单元格中的…

数据结构之动态顺序表(附带完整程序)

&#x1f388;基本概念 &#x1f308;一.线性表、顺序表的定义 ☀️&#xff08;1&#xff09;线性表&#xff1a; 是n个具有相同特性的数据元素的有限序列。线性表在逻辑上是线性结构&#xff0c;但在物理上存储时&#xff0c;通常以数组和链式结构的形式存储。 ☀️&…

c# 此程序集中已使用了资源标识符

严重性 代码 说明 项目 文件 行 禁止显示状态 错误 CS1508 此程序集中已使用了资源标识符“BMap.NET.WindowsForm.BMapControl.resources” BMap.NET.WindowsForm D:\MySource\Decompile\BMap.NET.WindowsForm\CSC 1 活动 运行程序时&a…

Mock-MOCO使用过程

一、jar包下载&#xff1a;https://github.com/dreamhead/moco 二、准备mock的json文件 data.json内容&#xff1a; ####GET请求 [{"description": "response使用Content-Type为charsetGBK编码格式来查看返回信息为中文的内容","request": {&q…

《Elasticsearch 源码解析与优化实战》第5章:选主流程

《Elasticsearch 源码解析与优化实战》第5章&#xff1a;选主流程 - 墨天轮 一、简介 Discovery 模块负责发现集群中的节点&#xff0c;以及选择主节点。ES 支持多种不同 Discovery 类型选择&#xff0c;内置的实现称为Zen Discovery ,其他的包括公有云平台亚马逊的EC2、谷歌…

Ansible单yaml文件部署Zabbix5.0监控平台

文章目录 Ansible单yaml文件部署Zabbix5.0监控平台节点规划案例实施基础环境准备编写剧本文件ZabbixWeb界面(1)改中文(2)添加监控主机 Ansible单yaml文件部署Zabbix5.0监控平台 节点规划 IP主机名节点192.168.200.10ansibleAnsible节点192.168.200.20zabbix-serverZabbix-ser…

深度学习入门(一):神经网络基础

一、深度学习概念 1、定义 通过训练多层网络结构对位置数据进行分类或回归&#xff0c;深度学习解决特征工程问题。 2、深度学习应用 图像处理语言识别自然语言处理 在移动端不太好&#xff0c;计算量太大了&#xff0c;速度可能会慢 eg.医学应用、自动上色 3、例子 使用…

Effective Java 案例分享(八)

39、使用注解而不是通过命名规则分类 如果需要对定义class&#xff0c;property&#xff0c;或者method进行分类管理&#xff0c;推荐的做法是使用注解对其添加类别&#xff0c;而不是通过命名规则分类。这里以JUnit为例&#xff1a; 在JUnit 3中&#xff0c;如果要写测试的方…

linux环境安装mysql数据库

一&#xff1a;查看是否自带mariadb数据库 命令&#xff1a;rpm -qa | grep mariadb 如果自带数据库则卸载掉重新安装 命令&#xff1a;yum remove mariadb-connector-c-3.1.11-2.el8_3.x86_64 二&#xff1a;将压缩文件上传到/user/local/mysql文件夹 或者直接下载 命令&a…

基于ssm+mysql+html道路养护管理系统

基于ssmmysqlhtml道路养护管理系统 一、系统介绍二、功能展示1.道路信息管理2.损害类型信息管理3.损害类型信息管理4.评定等级信息管理5.日常巡查信息管理6.定期检查信息管理 四、获取源码 一、系统介绍 系统主要功能&#xff1a;道路信息管理、损害类型信息管理、评定等级信息…

【网络原理】 (1) (应用层 传输层 UDP协议 TCP协议 TCP协议段格式 TCP内部工作机制 确认应答 超时重传 连接管理)

文章目录 应用层传输层UDP协议TCP协议TCP协议段格式TCP内部工作机制确认应答超时重传 网络原理部分我们主要学习TCP/IP协议栈这里的关键协议(TCP 和 IP),按照四层分别介绍.(物理层,我们不涉及). 应用层 我们需要学会自定义一个应用层协议. 自定义协议的原因? 当前的软件(应用…

【JAVASE】顺序和选择结构

⭐ 作者&#xff1a;小胡_不糊涂 &#x1f331; 作者主页&#xff1a;小胡_不糊涂的个人主页 &#x1f4c0; 收录专栏&#xff1a;浅谈Java &#x1f496; 持续更文&#xff0c;关注博主少走弯路&#xff0c;谢谢大家支持 &#x1f496; 顺序和选择 1. 顺序结构2. 分支结构2.1 …

Ubuntu18.04 下配置Clion

配置Clion 安装gcc、g、make Ubuntu中用到的编译工具是gcc©&#xff0c;g&#xff08;C&#xff09;&#xff0c;make(连接)。因此只需安装对应的工具包即可。Ubuntu下使用命令安装这些包&#xff1a; &#xff08;1&#xff09;安装gcc sudo apt install gcc&am…

解决Cannot resolve plugin org.apache.maven.plugins:xxxxxxxx

解决Cannot resolve plugin org.apache.maven.plugins:xxxxxxxx 方法一、检查配置设置 下图中三个方框圈出来的地方设置为自己的下载的maven地址&#xff0c;配置文件地址&#xff0c;仓库地址。刷新maven。 我个人试过没用&#xff0c;不过网上有的朋友用这个方法解决了。 …

Day 69-70:矩阵分解

代码&#xff1a; package dl;import java.io.*; import java.util.Random;/** Matrix factorization for recommender systems.*/public class MatrixFactorization {/*** Used to generate random numbers.*/Random rand new Random();/*** Number of users.*/int numUsers…

FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法

FANUC机器人实现2个RO输出信号互锁关联(互补)的具体方法 一般情况下,为了方便用户控制工装夹具上的电磁阀等控制工具,FANUC机器人出厂时给我们提供了8个RO输出信号,如下图所示,这8个RO信号可以各自单独使用。 那么,如果为了安全控制,需要将2个RO信号成对的进行安全互锁…

linux服务器安装redis

一、安装下载 下载安装参考文章 下载安装包地址&#xff1a;https://download.redis.io/releases/ 亲测有效&#xff0c;但是启动的步骤有一些问题 安装完成&#xff01;&#xff01;&#xff01; 二、启动 有三种启动方式 默认启动指定配置启动开机自启 说明&#xff1a…

下载JMeter的历史版本——个人推荐5.2.1版本

官网地址&#xff1a;https://archive.apache.org/dist/jmeter/binaries/