面试官问我按钮级别权限怎么控制,我说v-if,面试官说再见
最近的面试中有一个面试官问我按钮级别的权限怎么控制,我说直接v-if啊,他说不够好,我说我们项目中按钮级别的权限控制情况不多,所以v-if就够了,他说不够通用,最后他对我的评价是做过很多东西,但是都不够深入,好吧,那今天我们就来深入深入。
因为我自己没有相关实践,所以接下来就从这个有16.2k星星的后台管理系统项目Vue vben admin中看看它是如何做的。
获取权限码
要做权限控制,肯定需要一个code,无论是权限码还是角色码都可以,一般后端会一次性返回,然后全局存储起来就可以了,Vue vben admin是在登录成功以后获取并保存到全局的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);}}
})
接下来它提供了三种按钮级别的权限控制方式,一一来看。
函数方式
使用示例如下:
<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中获取当前用户的权限码列表,然后判断其中是否存在当前按钮需要的权限码,如果有多个权限码,只要满足其中一个就可以。
组件方式
除了通过函数方式使用,也可以使用组件方式,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包裹的内容,否则就啥也不渲染。
指令方式
最后一种就是指令方式,使用示例如下:
<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方法,判断当前用户是否存在通过指令插入的按钮需要的权限码,如果不存在,直接移除绑定的元素。
很明显,Vue vben admin的实现有两个问题,一是不能动态更改按钮的权限,二是动态更改当前用户的权限也不会生效。
解决第一个问题很简单,因为上述只有删除元素的逻辑,没有加回来的逻辑,那么增加一个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)
}
主要就是要把父节点保存起来,不然想再添加回去的时候获取不到原来的父节点,另外删除的时候创建一个注释节点给自己占位,这样下次想要回去能知道自己原来在哪。
第二个问题的原因是修改了用户权限数据,但是不会触发按钮的重新渲染,那么我们就需要想办法能让它触发,这个可以使用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方法的重新运行。
好了,深入完了,看着似乎也挺简单的,我不确定这些是不是面试官想要的,或者还有其他更高级更优雅的实现呢,知道的朋友能否指点一二,在下感激不尽。
相关文章:
面试官问我按钮级别权限怎么控制,我说v-if,面试官说再见
最近的面试中有一个面试官问我按钮级别的权限怎么控制,我说直接v-if啊,他说不够好,我说我们项目中按钮级别的权限控制情况不多,所以v-if就够了,他说不够通用,最后他对我的评价是做过很多东西,但…...
阿里云服务器使用教程:CentOS 7安装nginx详细步骤
目录 1、下载nginx压缩包 2、配置nginx安装所需环境 3、解压nginx压缩包 4、编译安装nginx 5、nginx启动...
Android JNI浅析、Java和Native通信对象的传值和回调
简单了解一下jni JNI是一个本地编程接口,它允许运行在Java虚拟机的Java代码与用其他语言(如C,C和汇编)编写的库交互。 jni函数签名 首先看一下java类型对应的jni类型: Java类型符号BooleanZByteBCharCShortSIntILongJFloatFDo…...
linux目录/usr/lib/systemd/system目录详解
文章目录前言一. systemd介绍二. service 脚本详解2.1 [Unit] 区块2.2 [Service] 区块2.3 [Install] 区块总结前言 init的进化经历了这么几个阶段: CentOS 5: SysV init,串行 CentOS 6:Upstart,并行,借鉴ubuntu CentOS 7:Syste…...
408考研计算机之计算机组成与设计——知识点及其做题经验篇目4:CPU的功能和基本结构
随着考研的慢慢复习,我们逐渐进入了计算机组成与设计的第五章中央处理器。它原名为CPU。姓C,名PU,字中央处理器,号计组难点,乃计算机之中心与核心部件,小编称之曰能算能控,赐名曰九天宏教普济生…...
2022-12-10青少年软件编程(C语言)等级考试试卷(五级)解析
2022-12-10青少年软件编程(C语言)等级考试试卷(五级)解析T1、漫漫回国路 2020年5月,国际航班机票难求。一位在美国华盛顿的中国留学生,因为一些原因必须在本周内回到北京。现在已知各个机场之间的航班情况,求问他回不回得来(不考虑转机次数和机票价格)。 时间限制:10…...
刷题专练之链表(一)
文章目录前言一、 移除链表元素1.题目介绍2.思路3.代码二、反转链表1.题目介绍2.思路3.代码三、链表的中间结点1.题目介绍2.思路3.代码四、链表的中间结点1.题目介绍2.思路3.代码前言 以下是链表经常考的面试题,我在这里进行归纳和讲解,采取的是循序渐进…...
elasticsearch高级查询api
yml配置 #es配置 spring:elasticsearch:rest:uris: 192.168.16.188:9200添加依赖 <dependency><groupId>org.elasticsearch.client</groupId><artifactId>elasticsearch-rest-high-level-client</artifactId> </dependency>使用编程的形式…...
力扣-股票的资本损益
大家好,我是空空star,本篇带大家了解一道简单的力扣sql练习题。 文章目录前言一、题目:1393. 股票的资本损益二、解题1.正确示范①提交SQL运行结果2.正确示范②提交SQL运行结果3.正确示范③提交SQL运行结果4.正确示范④提交SQL运行结果5.其他…...
蓝桥杯刷题冲刺 | 倒计时26天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.路径2.特别数的和3.MP3储存4.求和1.路径 题目 链接: 路径 - 蓝桥云课 (lanqiao.cn…...
嵌入式软件开发之Linux 用户权限管理
目录 Ubuntu 用户系统 权限管理 权限管理命令 权限修改命令 chmod 文件归属者修改命令 chown Ubuntu 用户系统 Ubuntu 是一个多用户系统,我们可以给不同的使用者创建不同的用户账号,每个用户使用各自的账号登陆,使用用户账号的目的一是方便…...
2023-03-15 RabbitMQ
RabbitMQ整合 官网erlang版本 : 20.3.8.x 官方rabbitMq版本: rabbitmq-server-generic-unix-3.7.14.tar.xz 1.安装 1.1 安装erlang 1.安装环境 yum -y install make gcc gcc-c kernel-devel m4 ncurses-devel openssl-devel2.在/usr/local/下创建erlangapp文件…...
二叉树链式结构的实现
文章目录1.二叉树的遍历1.1前序、中序以及后序遍历1.2代码测试1.3层序遍历1.4二叉树遍历习题2.节点个数以及高度2.1二叉树节点个数2.2叶子节点个树2.3第k层节点个数2.4树的高度1.二叉树的遍历 1.1前序、中序以及后序遍历 学习二叉树结构,最简单的方式就是遍历。所…...
蓝桥杯刷题冲刺 | 倒计时28天
作者:指针不指南吗 专栏:蓝桥杯倒计时冲刺 🐾马上就要蓝桥杯了,最后的这几天尤为重要,不可懈怠哦🐾 文章目录1.卡片2.数字三角形3.购物单4.回文日期1.卡片 题目 链接: 卡片 - 蓝桥云课 (lanqiao…...
一文带你吃透操作系统
文章目录1. 进程、线程管理2. 内存管理3. 进程调度算法4. 磁盘调度算法5. 页面置换算法6. 网络系统7. 锁8. 操作系统知识点文章字数大约1.9万字,阅读大概需要65分钟,建议收藏后慢慢阅读!!!1. 进程、线程管理 进程和线程…...
计算机网络英文简称汇总
分类名词全拼汉译概述B2CBusiness-to-Consumer商对客概述P2PPeer-to-Peer对等概述C/SClient-Server服务器-客户机概述ITUInternational Telecommunication Union国际电信联盟概述IEEEInstitute of Electrical and Electronics Engineers电气与电子工程师协会概述ICCCInternatio…...
腾讯云云服务器标准型S5性能配置简单测评
腾讯云服务器标准型S5实例CPU采用Intel Xeon Cascade Lake或者Intel Xeon Cooper Lake处理器,主频2.5GHz,睿频3.1GHz,标准型S5云服务器基于全新优化虚拟化平台,配有全新的Intel Advanced Vector Extension (AVX-512) 指令集&#…...
RK3568平台开发系列讲解(Linux系统篇)消息队列
🚀返回专栏总目录 文章目录 一、创建消息队列二、发送和接收消息三、内核结构沉淀、分享、成长,让自己和他人都能有所收获!😄 📢消息队列在如下两个方面上比管道有所增强: 消息队列中的数据是有边界的,发送端和接收端能以消息为单位进行交流,而不再是无分隔的字节流…...
2021电赛国一智能送药小车(F题)设计报告
2021电赛国一智能送药小车(F题)设计报告 【写在前面的话】 电赛是一个很奇妙的过程,可能有些人觉得电赛的门槛太高,那便意味着,当你决定要参加电赛的那一刻起,这一段路、这些日子就注定不会太轻松…...
刚工作3天就被裁了....
前言 还有谁?刚上三天班就被公司公司的工作不适合我,叫我先提升一下。 后面我也向公司那边讨要了一个说法,我只能说他们那边的说辞让我有些不服气。 现在之所以把这件事上记录一下,一是记录一下自己的成长轨迹,二是…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
python打卡day49
知识点回顾: 通道注意力模块复习空间注意力模块CBAM的定义 作业:尝试对今天的模型检查参数数目,并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...
【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...
【Linux】C语言执行shell指令
在C语言中执行Shell指令 在C语言中,有几种方法可以执行Shell指令: 1. 使用system()函数 这是最简单的方法,包含在stdlib.h头文件中: #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...
srs linux
下载编译运行 git clone https:///ossrs/srs.git ./configure --h265on make 编译完成后即可启动SRS # 启动 ./objs/srs -c conf/srs.conf # 查看日志 tail -n 30 -f ./objs/srs.log 开放端口 默认RTMP接收推流端口是1935,SRS管理页面端口是8080,可…...
Java 加密常用的各种算法及其选择
在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。 一、对称加密算法…...
以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...
Spring AI Chat Memory 实战指南:Local 与 JDBC 存储集成
一个面向 Java 开发者的 Sring-Ai 示例工程项目,该项目是一个 Spring AI 快速入门的样例工程项目,旨在通过一些小的案例展示 Spring AI 框架的核心功能和使用方法。 项目采用模块化设计,每个模块都专注于特定的功能领域,便于学习和…...
【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
