【vue】vue中按钮权限控制:
文章目录
- 一、获取权限码
- 二、三种按钮级别的权限控制方式
- 【1】函数方式
- 【2】组件方式
- 【3】指令方式
一、获取权限码
要做权限控制,肯定需要一个code,无论是权限码还是角色码都可以,一般后端会一次性返回,然后全局存储起来就可以了,在登录成功以后获取并保存到全局的store中:
import { defineStore } from 'pinia';
export const usePermissionStore = defineStore({state: () => ({// 权限代码列表permCodeList: [],}),getters: {// 获取getPermCodeList(){return this.permCodeList;}, },actions: {// 存储setPermCodeList(codeList) {this.permCodeList = codeList;},// 请求权限码async changePermissionCode() {const codeList = await getPermCode();this.setPermCodeList(codeList);}}
})
二、三种按钮级别的权限控制方式
【1】函数方式
使用示例如下:
<template><a-button v-if="hasPermission(['20000', '2000010'])" color="error" class="mx-4">拥有[20000,2000010]code可见</a-button>
</template><script lang="ts">import { usePermission } from '/@/hooks/web/usePermission';export default defineComponent({setup() {const { hasPermission } = usePermission();return { hasPermission };},});
</script>
本质上就是通过v-if,只不过是通过一个统一的权限判断方法hasPermission:
export function usePermission() {function hasPermission(value, def = true) {// 默认视为有权限if (!value) {return def;}const allCodeList = permissionStore.getPermCodeList;if (!isArray(value)) {return allCodeList.includes(value);}// intersection是lodash提供的一个方法,用于返回一个所有给定数组都存在的元素组成的数组return (intersection(value, allCodeList)).length > 0;return true;}
}
很简单,从全局store中获取当前用户的权限码列表,然后判断其中是否存在当前按钮需要的权限码,如果有多个权限码,只要满足其中一个就可以。
【2】组件方式
除了通过函数方式使用,也可以使用组件方式,Vue vben admin提供了一个Authority组件,使用示例如下:
<template><div><Authority :value="RoleEnum.ADMIN"><a-button type="primary" block> 只有admin角色可见 </a-button></Authority></div>
</template>
<script>import { Authority } from '/@/components/Authority';import { defineComponent } from 'vue';export default defineComponent({components: { Authority },});
</script>
使用Authority包裹需要权限控制的按钮即可,该按钮需要的权限码通过value属性传入,接下来看看Authority组件的实现。
<script lang="ts">import { defineComponent } from 'vue';import { usePermission } from '/@/hooks/web/usePermission';import { getSlot } from '/@/utils/helper/tsxHelper';export default defineComponent({name: 'Authority',props: {value: {type: [Number, Array, String],default: '',},},setup(props, { slots }) {const { hasPermission } = usePermission();function renderAuth() {const { value } = props;if (!value) {return getSlot(slots);}return hasPermission(value) ? getSlot(slots) : null;}return () => {return renderAuth();};},});
</script>
同样还是使用hasPermission方法,如果当前用户存在按钮需要的权限码时就原封不动渲染Authority包裹的内容,否则就啥也不渲染。
【3】指令方式
使用示例如下:
<a-button v-auth="'1000'" type="primary" class="mx-4"> 拥有code ['1000']权限可见 </a-button>
实现如下:
import { usePermission } from '/@/hooks/web/usePermission';function isAuth(el, binding) {const { hasPermission } = usePermission();const value = binding.value;if (!value) return;if (!hasPermission(value)) {el.parentNode?.removeChild(el);}
}const mounted = (el, binding) => {isAuth(el, binding);
};const authDirective = {// 在绑定元素的父组件// 及他自己的所有子节点都挂载完成后调用mounted,
};
// 注册全局指令
export function setupPermissionDirective(app) {app.directive('auth', authDirective);
}
只定义了一个mounted钩子,也就是在绑定元素挂载后调用,依旧是使用hasPermission方法,判断当前用户是否存在通过指令插入的按钮需要的权限码,如果不存在,直接移除绑定的元素。
很明显,权限控制的实现有两个问题,一是不能动态更改按钮的权限,二是动态更改当前用户的权限也不会生效。
【1】解决第一个问题很简单,因为上述只有删除元素的逻辑,没有加回来的逻辑,那么增加一个updated钩子:
app.directive("auth", {mounted: (el, binding) => {const value = binding.valueif (!value) returnif (!hasPermission(value)) {// 挂载的时候没有权限把元素删除removeEl(el)}},updated(el, binding) {// 按钮权限码没有变化,不做处理if (binding.value === binding.oldValue) return// 判断用户本次和上次权限状态是否一样,一样也不用做处理let oldHasPermission = hasPermission(binding.oldValue)let newHasPermission = hasPermission(binding.value)if (oldHasPermission === newHasPermission) return// 如果变成有权限,那么把元素添加回来if (newHasPermission) {addEl(el)} else {// 如果变成没有权限,则把元素删除removeEl(el)}},
})const hasPermission = (value) => {return [1, 2, 3].includes(value)
}const removeEl = (el) => {// 在绑定元素上存储父级元素el._parentNode = el.parentNode// 在绑定元素上存储一个注释节点el._placeholderNode = document.createComment("auth")// 使用注释节点来占位el.parentNode?.replaceChild(el._placeholderNode, el)
}const addEl = (el) => {// 替换掉给自己占位的注释节点el._parentNode?.replaceChild(el, el._placeholderNode)
}
主要就是要把父节点保存起来,不然想再添加回去的时候获取不到原来的父节点,另外删除的时候创建一个注释节点给自己占位,这样下次想要回去能知道自己原来在哪。
【2】第二个问题的原因是修改了用户权限数据,但是不会触发按钮的重新渲染,那么我们就需要想办法能让它触发,这个可以使用watchEffect方法,我们可以在updated钩子里通过这个方法将用户权限数据和按钮的更新方法关联起来,这样当用户权限数据改变了,可以自动触发按钮的重新渲染:
import { createApp, reactive, watchEffect } from "vue"
const codeList = reactive([1, 2, 3])const hasPermission = (value) => {return codeList.includes(value)
}app.directive("auth", {updated(el, binding) {let update = () => {let valueNotChange = binding.value === binding.oldValuelet oldHasPermission = hasPermission(binding.oldValue)let newHasPermission = hasPermission(binding.value)let permissionNotChange = oldHasPermission === newHasPermissionif (valueNotChange && permissionNotChange) returnif (newHasPermission) {addEl(el)} else {removeEl(el)}};if (el._watchEffect) {update()} else {el._watchEffect = watchEffect(() => {update()})}},
})
将updated钩子里更新的逻辑提取成一个update方法,然后第一次更新在watchEffect中执行,这样用户权限的响应式数据就可以和update方法关联起来,后续用户权限数据改变了,可以自动触发update方法的重新运行。
相关文章:
【vue】vue中按钮权限控制:
文章目录 一、获取权限码二、三种按钮级别的权限控制方式【1】函数方式【2】组件方式【3】指令方式 一、获取权限码 要做权限控制,肯定需要一个code,无论是权限码还是角色码都可以,一般后端会一次性返回,然后全局存储起来就可以了…...
【博客695】k8s subPathExpr作用
k8s subPathExpr作用 场景: 对于一个deployment或者job拉起的服务,所有pod都是一样的配置,如果都挂载了宿主机的同一个目录,那么就会互相干扰,我们希望挂载相同目录,且在这个目录下,每个pod建立…...
微信小程序中键盘弹起输入框自动跳到键盘上方处理
效果展示 键盘未弹起时 键盘弹起后: 实现方式 话就不多说了 我直接贴代码了 原理就是用你点击的输入框的底部 距离顶部的位置 减去屏幕高度除以2,然后设成负值,再将这个值给到最外层相对定位的盒子的top属性,这样就不会出现顶…...
excel将主信息和明细信息整理为多对多(每隔几行空白如何填充)
excel导出的数据是主信息和明细信息形式。 方法如下:1、首先,从第一个单元格开始选中要填充的数据区域。2、按CtrlG或者F5调出定位对话框,点击左下角的【定位条件】。3、在【定位条件】中选择【空值】,然后点击【确定】按钮。4、按照上述操作…...
卷积神经网络实现彩色图像分类 - P2
🍨 本文为🔗365天深度学习训练营 中的学习记录博客🍦 参考文章:365天深度学习训练营-第P2周:彩色识别🍖 原作者:K同学啊 | 接辅导、项目定制🚀 文章来源:K同学的学习圈子…...
【博客694】k8s kubelet 状态更新机制
k8s kubelet 状态更新机制 场景: 当 Kubernetes 中 Node 节点出现状态异常的情况下,节点上的 Pod 会被重新调度到其他节点上去,但是有的时候我们会发现节点 Down 掉以后,Pod 并不会立即触发重新调度,这实际上就是和 K…...
【博客692】grafana如何解决step动态变化时可能出现range duration小于step
grafana如何解决step动态变化时可能出现range duration小于step 1、grafana中的step和resolution grafana中的 “step” grafana本身是没有提供step参数的,因为仪表盘根据查询数据区间以及仪表盘线条宽度等,对于不同查询,相同的step并不能…...
eNSP:ibgp的破水平切割练习
实验要求: 拓扑展示: 命令操作: R1: <Huawei>sys [Huawei]sys r1 [r1]int g 0/0/1 [r1-GigabitEthernet0/0/1]ip add 12.1.1.1 24 [r1-GigabitEthernet0/0/1]int lo0 [r1-LoopBack0]ip add 1.1.1.1 24 [r1-LoopBack0]osp…...
maven是什么?安装+配置
目录 1.什么是maven? 1.2.maven的核心功能是什么? 2.Maven安装配置 2.1Maven的安装 2.2Maven环境配置 1.配置 MAVEN_HOME ,变量值就是你的 maven 安装的路径(bin 目录之前一级目录) 2.将MAVEN_HOME 添加到Path系…...
基于长短期神经网络LSTM的多分类代码
目录 背影 摘要 LSTM的基本定义 LSTM实现的步骤 基于长短期神经网络LSTM的股票预测 MATALB编程实现,附有代码:基于长短期神经网络LSTM的多分类代码,基于LSTM的多分类预测-深度学习文档类资源-CSDN文库 https://download.csdn.net/download/abc991835105/88184779 效果图 结果…...
利用爬虫爬取图片并保存
1 问题 在工作中,有时会遇到需要相当多的图片资源,可是如何才能在短时间内获得大量的图片资源呢? 2 方法 我们知道,网页中每一张图片都是一个连接,所以我们提出利用爬虫爬取网页图片并下载保存下来。 首先通过网络搜索…...
设计模式之Bridge模式的C++实现
目录 1、Bridge模式的提出 2、Bridge模式的定义 3、Bridge模式总结 4、需求描述 5、多继承方式实现 6、使用Bridge设计模式实现 1、Bridge模式的提出 在软件功能模块设计中,如果类的实现功能划分不清晰,使得继承得到的子类往往是随着需求的变化&am…...
springboot异步任务
在Service类声明一个注解Async作为异步方法的标识 package com.qf.sping09test.service;import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service;Service public class AsyncService {//告诉spring这是一个异步的方法Asyncp…...
Flutter父宽度自适应子控件的宽度
需求: 控件随着金币进行自适应宽度 image.png 步骤: 1、Container不设置宽度,需要设置约束padding; 2、文本使用Flexible形式; Container(height: 24.dp,padding: EdgeInsetsDirectional.only(start: 8.dp, end: 5.d…...
什么是 API 安全?学习如何防止攻击和保护数据
随着 API 技术的普及,API 安全成为了一个越来越重要的问题。本文将介绍什么是 API 安全,以及目前 API 面临的安全问题和相应的解决方案。 什么是 API 安全 API 安全是指保护 API 免受恶意攻击和滥用的安全措施。API 安全通常包括以下几个方面࿱…...
简述 TCP 和 UDP 的区别以及优缺点和使用场景?
一、TCP与UDP区别总结: 1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接 2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失&…...
react进阶
react-virtualized的高阶组件,Autosize可以使屏幕适配。使用render-props模式来获取到AutoSizer组件暴露的width和height属性。JSON.parse(JSON.stringify())不适用于有undefined的数据。 深拷贝的使用,不能使用在有undefined的数据中。有直接过滤undefi…...
使用windows搭建WebDAV服务,并内网穿透公网访问【无公网IP】
文章目录 1. 安装IIS必要WebDav组件2. 客户端测试3. 使用cpolar内网穿透,将WebDav服务暴露在公网3.1 打开Web-UI管理界面3.2 创建隧道3.3 查看在线隧道列表3.4 浏览器访问测试 4. 安装Raidrive客户端4.1 连接WebDav服务器4.2 连接成功4.2 连接成功 1. Linux(centos8…...
科技感响应式管理系统后台登录页ui设计html模板
做了一个科技感的后台管理系统登录页设计,并且尝试用响应式布局把前端html写了出来,发现并没有现象中的那么容易,chrome等标准浏览器都显示的挺好,但IE11下面却出现了很多错位,兼容起来还是挺费劲的,真心不…...
Lombok的使用及注解含义
文章目录 一、简介二、如何使用2.1、在IDEA中安装Lombok插件2.2、添加maven依赖 三、常用注解3.1、Getter / Setter3.2、ToString3.3、NoArgsConstructor / AllArgsConstructor3.4、EqualsAndHashCode3.5、Data3.6、Value3.7、Accessors3.7.1、Accessors(chain true)3.7.2、Ac…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?
编辑:陈萍萍的公主一点人工一点智能 未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战,在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...
业务系统对接大模型的基础方案:架构设计与关键步骤
业务系统对接大模型:架构设计与关键步骤 在当今数字化转型的浪潮中,大语言模型(LLM)已成为企业提升业务效率和创新能力的关键技术之一。将大模型集成到业务系统中,不仅可以优化用户体验,还能为业务决策提供…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
多场景 OkHttpClient 管理器 - Android 网络通信解决方案
下面是一个完整的 Android 实现,展示如何创建和管理多个 OkHttpClient 实例,分别用于长连接、普通 HTTP 请求和文件下载场景。 <?xml version"1.0" encoding"utf-8"?> <LinearLayout xmlns:android"http://schemas…...
spring:实例工厂方法获取bean
spring处理使用静态工厂方法获取bean实例,也可以通过实例工厂方法获取bean实例。 实例工厂方法步骤如下: 定义实例工厂类(Java代码),定义实例工厂(xml),定义调用实例工厂ÿ…...
在Ubuntu中设置开机自动运行(sudo)指令的指南
在Ubuntu系统中,有时需要在系统启动时自动执行某些命令,特别是需要 sudo权限的指令。为了实现这一功能,可以使用多种方法,包括编写Systemd服务、配置 rc.local文件或使用 cron任务计划。本文将详细介绍这些方法,并提供…...
Rust 异步编程
Rust 异步编程 引言 Rust 是一种系统编程语言,以其高性能、安全性以及零成本抽象而著称。在多核处理器成为主流的今天,异步编程成为了一种提高应用性能、优化资源利用的有效手段。本文将深入探讨 Rust 异步编程的核心概念、常用库以及最佳实践。 异步编程基础 什么是异步…...
浪潮交换机配置track检测实现高速公路收费网络主备切换NQA
浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求,本次涉及的主要是收费汇聚交换机的配置,浪潮网络设备在高速项目很少,通…...
站群服务器的应用场景都有哪些?
站群服务器主要是为了多个网站的托管和管理所设计的,可以通过集中管理和高效资源的分配,来支持多个独立的网站同时运行,让每一个网站都可以分配到独立的IP地址,避免出现IP关联的风险,用户还可以通过控制面板进行管理功…...
