Vue3+Element+TS动态菜单+按钮权限控制实现探索

1.动态获取权限并根据获取权限转换成相对应的router

根据请求获取菜单数据,对菜单数据进行转换,分别进行下面几步:

/*** 组件地址前加斜杠处理*/
export function addSlashToRouteComponent(routeList: AppRouteRecordRaw[]) {routeList.forEach((route) => {const component = route.component as string;if (component) {const layoutFound = LayoutMap.get(component);if (!layoutFound) {route.component = component.startsWith("/") ? component : `/${component}`;}}route.children && addSlashToRouteComponent(route.children);});return routeList;
}

利用import函数+通配符,引入匹配的所有vue页面,如下:

const LayoutMap = new Map<string, () => Promise<typeof import("*.vue")>>();

以及const dynamicViewsModules = import.meta.glob("../../views/**/*.{vue,tsx}");

该map会生成一个以页面路径为key的,带有@import动态引入的方法为值的对象,这是可以通过处理key字符串,通过获取的菜单列表匹配对应的path,最终的component 就等于dynamicViewsModules[path]

function dynamicImport(dynamicViewsModules: Record<string, () => Promise<Recordable>>, component: string) {const keys = Object.keys(dynamicViewsModules);const matchKeys = keys.filter((key) => {const k = key.replace("../../views", "");const startFlag = component.startsWith("/");const endFlag = component.endsWith(".vue") || component.endsWith(".tsx");const startIndex = startFlag ? 0 : 1;const lastIndex = endFlag ? k.length : k.lastIndexOf(".");return k.substring(startIndex, lastIndex) === component;});if (matchKeys?.length === 1) {const matchKey = matchKeys[0];return dynamicViewsModules[matchKey];} else if (matchKeys?.length > 1) {console.log("Please do not create `.vue` and `.TSX` files with the same file name in the same hierarchical directory under the views folder. This will cause dynamic introduction failure");return;}
}

处理后最终返回的数据就是生成router树状结构 

2.动态添加路由addRoute

const menuRecordRoutes: RouteRecordRaw[] = Object.entries(menuRoutes).map(([, config]) => config).sort((a: any, b: any) => a.order - b.order) as RouteRecordRaw[];
menuRecordRoutes.forEach((route) => {router.addRoute(route);});

这里有个值得注意的地方如果是该菜单列表下有多个子菜单需要将子菜单也添加进去,如:

menuRecordRoutes.forEach((route) => {router.addRoute(route);if (route?.children?.length) {route.children.forEach((child) => {child.name = route.name?.toString() + "-" + child.name?.toString();if (route.name) {router.addRoute(route.name, child);}});}});

上图中后面一个router.addRoute是针对每个子菜单进行router添加,并且这里还有一个坑:

如果不同的菜单下的子菜单的name属性是一样的话 这里可能会把前面一个添加的子菜单给覆盖了,因为router中的name 属性是唯一的,所以这里对子菜单的name做了一个拼接:将父菜单名称和子菜单名称拼接到一起作为子菜单的新名称。另外这个name属性非常重要,如果name属性中含有特殊符号(如:name=detail@id),页面中如果使用了类似这样的页面跳转:router.push({ name: "detail", params: { id: row.id } }); 则会导致路由不匹配的问题

3.自定义指令控制按钮显隐 

//main.ts中引用
const app = createApp(App);
// 全局注册 自定义指令(directive)
setupDirective(app);
import type { App } from "vue";import { hasPerm } from "./permission";// 全局注册 directive
export function setupDirective(app: App<Element>) {// 使 v-hasPerm 在所有组件中都可用app.directive("hasPerm", hasPerm);
}
//自定义指令的自定义方法
export const hasPerm: Directive = {mounted(el: HTMLElement, binding: DirectiveBinding) {// 「超级管理员」拥有所有的按钮权限const { authList } = useUserStoreHook();const { value } = binding;let result = false;if (authList.length && value) {if (Array.isArray(value)) {result = value.every((ele) => authList.includes(ele));} else {result = authList.includes(value);}}if (!result) {el.parentNode && el.parentNode.removeChild(el);}return result;},
};

页面中使用

<el-button v-hasPerm="['xxx']" :icon="Delete" size="small" text type="primary">删 除</el-button>

至此,动态菜单和按钮权限功能完成 

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

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

相关文章

如何创建族表

https://jingyan.baidu.com/article/c275f6bafa5714a23c756768.html

五角钱的程序员 | Kafka 是什么?

本文来源公众号“五角钱的程序员”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;Kafka 是什么&#xff1f; 你是一个程序员&#xff0c;假设你维护了两个服务 A 和 B。B 服务每秒只能处理 100 个消息&#xff0c;但 A 服务却每秒…

数据结构·一篇搞定栈!

好久不见&#xff0c;超级想念 废话不多说&#xff0c;直接看 引言 在数据结构的大家族中&#xff0c;栈&#xff08;Stack&#xff09;是一种非常重要的线性数据结构&#xff0c;它的特点是后进先出&#xff08;LIFO&#xff0c;Last In First Out&#xff09;。栈在程序设…

Echarts旭日图的配置项,强大的层级关系展示图表。

ECharts中的旭日图&#xff08;Sunburst Chart&#xff09;是一种数据可视化图表&#xff0c;用于展示层级关系数据。它通常用于呈现树状结构或层级结构的数据&#xff0c;例如组织结构、文件目录结构、地理区域层级等。 旭日图通过圆形的方式展示数据的层级结构&#xff0c;每…

【Qt 学习笔记】Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt常用控件 | 布局管理器 | 水平布局Horizontal Layout 文章编号&…

算法day01

1、[283.移动零](https://leetcode.cn/problems/move-zeroes/) 给定一个数组 nums&#xff0c;编写一个函数将所有 0 移动到数组的末尾&#xff0c;同时保持非零元素的相对顺序。请注意 &#xff0c;必须在不复制数组的情况下原地对数组进行操作。 解题思路&#xff1a; 双指针…

Redis——入门简介

Redis&#xff0c;全称为Remote Dictionary Server&#xff0c;即远程字典服务&#xff0c;是一个开源的、内存中的数据结构存储系统。它可以用作数据库、缓存和消息中间件&#xff0c;具备出色的读写性能和丰富的功能特性。以下是对Redis的入门简介&#xff1a; 一、Redis的主…

LVM逻辑卷管理之快照 —— 筑梦之路

简介 LVM快照是LVM提供的一个强大功能&#xff0c;它允许我们在不中断服务的情况下捕获逻辑卷在某个时间点的状态&#xff0c;从而进行备份、恢复或测试等操作。LVM快照是一个特殊的逻辑卷&#xff0c;它保存了原始逻辑卷在某个时间点的数据镜像。快照使用写时复制&#xff08…

IT项目管理-小题计算【太原理工大学】

1.合同总价问题 问承包商的利润是&#xff1f; 实际利润目标利润&#xff08;目标成本-实际成本&#xff09;*卖方分担比例 解&#xff1a;10 000&#xff08;100 000 - 90 000&#xff09;* 0.2 12 000&#xff08;元&#xff09; 实际成本有时也写作最终成本&#xff0c;问承…

Ubuntu 24.04 LTS 安装 touchegg 开启触控板多指手势

文章目录 〇、概述一、安装 touchegg二、安装 gnome-shell 扩展 X11 Gestures三、安装可视化配置工具 touche 〇、概述 之前为了让笔记本支持多指手势&#xff0c;我安装的是 fusuma&#xff0c;安装教程详见 这篇文章 &#xff0c;考虑到 fusuma 安装过程繁琐且不支持可视化配…

Qt自定义控件--提升为

为什么要自定义控件 1&#xff0c;有复合小控件需要组合为一个整体控件时&#xff1b; 2&#xff0c;一个复合控件需要重复使用时&#xff1b; 实现 自定义控件文件 新增三个文件 关联不同组的控件 关联之前的准备工作 1&#xff0c;在主控件选择和子控件所有控件所在控件…

linux 设备驱动支持多个设备写法

compatible “aaa,bbb” 当一个驱动支持多个设备的时候&#xff0c;在每个设备的dts中&#xff0c;都会配置各自的compatible&#xff0c;当与driver中的compatible匹配后&#xff0c;会取各自的data。在 __of_match_node中有match。 Example1 static const struct of_devi…

Docker与Consul:构建动态服务发现与更新的微服务体系

Docker和Consul是构建微服务体系中常用的工具之一&#xff0c;它们可以协同工作来实现动态服务发现和更新。下面是一个简单的Java微服务体系的示例&#xff0c;使用Docker容器和Consul进行服务的注册、发现和更新。 1. 创建一个简单的Java微服务 首先&#xff0c;我们创建一个…

1.4. 离散时间鞅-鞅的Lp收敛,鞅与停时 (2)

鞅的L^p收敛p > 1,鞅与停时 鞅的L^p收敛(p > 1),鞅与停时2. 极大值不等式2.1. Doob不等式-时间有界2.2. L p L^{p} L

MySQL主从切换测试

测试主从高可用 确认mha正常运行中ps -ef | grep mha #一般在kde-offline3节点 mysql 166898 1 1 17:54 pts/0 00:00:00 perl /bin/masterha_manager --conf=/data/apps/mha4mysql-manager-0.58/app13306.cnf --ignore_last_failover 如果未启动则需要手动执行mha…

数据结构之----栈与队列

栈是限定仅在表尾进行插入和删除操作的线性表&#xff1b; 队列是只允许在一端进行插入操作&#xff0c;而另一端进行删除操作的线性表&#xff1b; 栈&#xff0c;允许插入和删除的一端称为栈顶&#xff0c;另一端称为栈底&#xff0c;特点后进先出。 插入操作称为进栈&#…

【全网首发】大模型入门、概念详解、综述

大模型教程 注NLP入门、大模型入门、NLP发展、NLP四范式、综述入门必读图像相关大模型相关微调相关多模态相关其他注 多数文章博主已经读完,有中文笔记、代码、私信博主领取也可以相互交流学习。笔记写在flowus中会逐渐迁移到博客。 NLP入门、大模型入门、NLP发展、NLP四范式…

for box,score,cat in zip(xywhboxes,scores,cats):

zip()函数可以将多个可迭代对象打包成一个元组序列&#xff0c;这些对象的元素会一一对应&#xff0c;例如&#xff1a; a [1, 2, 3] b [a, b, c] c zip(a, b) print(list(c)) 输出为 [(1, a), (2, b), (3, c)] for循环中的zip()函数将它们打包成一个元组序列&#xff0…

Android中C++如何读写json文件

我们需要在json文件中记录一下总数&#xff0c;文件格式如下&#xff1a; [{"total_count":0,"total_count1":0,"total_count2":0,"total_count3":0,"total_count4":0}] 目录 1. Android.bp中新增 2. 头文件添加 3. 向jso…

websocket和http协议的区别

ws(websocket)协议和http协议是两种不同的协议。 http&#xff1a;http是一种用于传输超文本的应用层协议&#xff0c;通常用于web端浏览器和web端服务器之间传输数据。http也是基于tcp的&#xff0c;但是HTTP只能在同一时刻单向发送消息&#xff0c;是一种半双工通信。&#…