Vue3后台管理-项目总结

后台管理

  • 1. 动态路由
  • 2. 动态侧边栏菜单

持续更新中。。。

1. 动态路由

  1. 后台路由模型数据 (如果后端不知道怎么转为 这种树结构的路由,可以参考 普通数组转树结构的数组)

    const dynamicRoutes = [{path: '/',name: 'Layout',redirect: '/home',component: 'Layout',meta: {label: '',icon: '',hidden: false,},children: [{path: '/home',name: 'Home',component: 'Home',meta: {label: '首页',icon: 'HomeFilled',hidden: false}},]},{path: '/perm',name: 'perm',component: 'Layout',redirect: '/perm/user',meta: {label: '权限管理',icon: 'Lock',hidden: false},children: [{path: '/perm/user',name: 'user',component: 'User',meta: {label: '用户管理',icon: 'User',hidden: false},},{path: '/perm/role',name: 'role',component: 'Role',meta: {label: '角色管理',icon: 'Avatar',hidden: false},},{path: '/perm/menu',name: 'permMenu',component: 'PermMenu',meta: {label: '菜单管理',icon: 'Grid',hidden: false},},]},// 这个路由不能放到,常量路由里面,必须放到动态路由// 原因:在刷新页面时,动态路由丢失,需要重新加载动态路由,//      因为当前还没有动态路由,只能重定向到404,//      所以即使后面动态路由加载成功,也不会再去重定向到 动态路由{path: '/:pathMatcher(.*)*',redirect: '/404',name: 'any',meta: {label: '',icon: '',hidden: true}},]
    
  2. 后台路由模型 转 前端需要的路由对象
    2.1 准备前端组件信息。这相当于是一个Map,在下面 转换 的时候会用到。

    import Layout from '@/layout/index.vue'
    import Home from '@/views/home/index.vue'
    import Screen from '@/views/screen/index.vue'
    import User from '@/views/perm/user/index.vue'
    import Role from '@/views/perm/role/index.vue'
    import PermMenu from '@/views/perm/menu/index.vue'export const allRouteComponents = {Layout,Home,Screen,User,Role,PermMenu,
    }
    

    2.2 转换操作

    // 将后端获取到的动态路由 添加到 router
    // 在路由守卫中使用,刷新页面时,重新添加动态路由,解决内存中路由丢失,白屏问题
    // 这里传入的路由数组就是后端传过来的
    const addRoutes = (routesArr) => {const routesObjArr = convertRoutes(routesArr)routesObjArr.forEach(item => {router.addRoute(item)})
    }// 将后端获取到的路由对象的 component(字符串类型) 转为 component(组件对象)
    const convertRoutes = (routesArr) => {return routesArr.map(item => {let routeObj = allRouteComponents[item.component]if (routeObj) {item.component = routeObj}if (item.children) {item.children = convertRoutes(item.children)}return item})
    }
    
  3. 动态路由添加 addRoutes()

    const userStore = useUserStore()
    const menuStore = useMenuStore()
    仓库函数的使用要写在 路由守卫里面,写在外面会报pinia没有激活错误。
    原因:
    1、 在项目启动时,仓库可能还没有被use,肯定会报错,
    2、 如果写在路由守卫里面,只有在切换路由的时候才会使用到仓库,这个时候仓库肯定已经被use了。

    registerFlag ,每次刷新页面这个值都会重新初始化为false,内存中路由也被清除。这个就需要重新添加 routes。添加routes后,registerFlag 置为 true。再执行路由切换不需要重复添加(只有刷新,才会重新触发)

    // 刷新页面时,重新添加动态路由
    const registerFlag = ref(false)router.beforeEach(async (to, from, next) => {const userStore = useUserStore()const menuStore = useMenuStore()// 判断用户是否登录if (userStore.token) {// 解决刷新页面,内存中路由丢失问题if (!registerFlag.value) {addRoutes(menuStore.userMenus)registerFlag.value = true// 添加完路由,重新访问目标页面await router.replace(to)}// 已经登录,访问/login,会重定向到 / (首页)if (to.path === '/login') {next('/home')} else {next()}} else {// 未登录if (to.path === '/login') {next()} else {// 重定向到/login,并追加一个 登录成功后重定向地址next({path: '/login', query: {redirect: to.path}})}}
    })
    

2. 动态侧边栏菜单

  1. 后端数据模型

    const dynamicRoutes = [{path: '/',name: 'Layout',redirect: '/home',component: 'Layout',meta: {label: '',icon: '',hidden: false,},children: [{path: '/home',name: 'Home',component: 'Home',meta: {label: '首页',icon: 'HomeFilled',hidden: false}},]},{path: '/perm',name: 'perm',component: 'Layout',redirect: '/perm/user',meta: {label: '权限管理',icon: 'Lock',hidden: false},children: [{path: '/perm/user',name: 'user',component: 'User',meta: {label: '用户管理',icon: 'User',hidden: false},},{path: '/perm/role',name: 'role',component: 'Role',meta: {label: '角色管理',icon: 'Avatar',hidden: false},},{path: '/perm/menu',name: 'permMenu',component: 'PermMenu',meta: {label: '菜单管理',icon: 'Grid',hidden: false},},]},// 这个路由不能放到,常量路由里面,必须放到动态路由// 原因:在刷新页面时,动态路由丢失,需要重新加载动态路由,//      因为当前还没有动态路由,只能重定向到404,//      所以即使后面动态路由加载成功,也不会再去重定向到 动态路由{path: '/:pathMatcher(.*)*',redirect: '/404',name: 'any',meta: {label: '',icon: '',hidden: true}},
    ]
    
  2. 后端路由数据–>过滤出hidden==false(用于侧边栏展示的)

    <script setup>
    import AsideMenu from '@/layout/menu/index.vue'
    import {computed,defineOptions} from "vue";
    defineOptions({name: 'Layout'})// 去 hidden 函数
    // 如果父路由 隐藏,那么子路由hidden不论true,false,都不会显示
    // 如果父路由 显示,那么子路由hidden为false会显示,hidden为true会隐藏
    const filterHiddenRoute = (routes) => {return routes.filter(item => {if (!item.meta.hidden) {if (item.children) {item.children = filterHiddenRoute(item.children)}return true} else {return false}})
    }
    // 去掉hidden后的菜单树
    // 这里传入的routes,就是后端传来的路由数组(树结构)
    const menuList = computed(() => {return filterHiddenRoute(routes)
    })
    </script>
    <template><el-menu><aside-menu :menuList="menuList"></aside-menu></el-menu>
    </template>
    
  3. 动态菜单递归组件定义

    递归菜单必须有组件名,用于在组件中调用自身

    <script setup>
    import router from '@/router'defineOptions({name: 'AsideMenu'})
    const menus = defineProps(['menuList'])// 跳转路由
    const goRoute = (e) => {router.push(e.index)
    }
    </script><template><template v-for="item of menus.menuList" :key="item.path"><!--     没有子菜单--><el-menu-item v-if="!item.children" :index="item.path" @click="goRoute"><el-icon><component :is="item.meta.icon"></component></el-icon><template #title><span>{{ item.meta.label }}</span></template></el-menu-item><!--     有子菜单,但是只有1个--><el-menu-item v-if="item.children && item.children.length===1" :index="item.children[0].path" @click="goRoute"><el-icon><component :is="item.children[0].meta.icon"></component></el-icon><template #title><span>{{ item.children[0].meta.label }}</span></template></el-menu-item><!--     有子菜单,子菜单大于1个--><el-sub-menu v-if="item.children && item.children.length>1" :index="item.path"><template #title><el-icon><component :is="item.meta.icon"></component></el-icon><span>{{ item.meta.label }}</span></template><AsideMenu :menuList="item.children"></AsideMenu></el-sub-menu></template>
    </template>
    <style scoped lang="scss">
    </style>
    

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

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

相关文章

如何在Ubuntu的Linux系统上搭建nacos集群

官方给出的集群部署架构图 集群部署说明 (nacos.io)3个或3个以上nacos节点才能构成集群当前示例中包含3个nacos节点&#xff0c;同时一个负载均衡器代理3个nacos&#xff0c;本示例中负载均衡器可使用的是nginx 准备并安装好正常运行的nginx&#xff0c;本示例略准备并安装好正…

Redis权限管理体系(一):客户端名及用户名

在Redis6之前的版本中&#xff0c;因安全认证的主要方式是使用Redis实例的密码进行基础控制&#xff0c;而无法按照不同的应用来源配置不同账号以及更细粒度的操作权限控制来管理。本文先从client list中的信息入手&#xff0c;逐步了解Redis的客户端名设置、用户设置及权限控制…

Numpy库

目录 介绍&#xff1a; 一、生成 1.1普通生成 1.2随机生成 1.3其它生成 二、访问 三、赋值 四、运算 五、其它 介绍&#xff1a; NumPy是一个用于数值计算的Python库&#xff0c;它提供了高效的多维数组对象&#xff08;ndarray&#xff09;、用于数组计算的函数以及用于…

【Monitor, Maintenance Operation, Script code/prgramme】

Summary of M,M&O,Program JD) Monitor & M&O Symbio信必优) Job chance/opportunities on Dec 12th, 20231.1) Content 招聘JD job description:1.2) suggestions from Ms Liang/Winnie on Wechat app1.3) Java微服务是什么&#xff1f;1.3.1) [URL Java 微服务](…

如何使用PHP创建RESTful API?

创建 RESTful API&#xff08;Representational State Transferful Application Programming Interface&#xff09;是通过 HTTP 协议提供对资源的访问和操作的一种常见方式。以下是使用 PHP 创建 RESTful API 的一般步骤&#xff1a; 步骤 1: 设计 API 路由 首先&#xff0c…

QT linux下使用Qt Creator调试附加进程,加快调试

文章目录 一、调试附加进程二、配置流程&#xff08;1&#xff09;开放linux内核配置项&#xff08;2&#xff09;命令行直接启动程序&#xff08;3&#xff09;调试附加到进程 一、调试附加进程 使用附加进程调试要比直接调试速度要快&#xff0c;但是不足之处是&#xff0c;…

京微齐力:基于H7的平衡控制系统(一、姿态解析)

目录 前言一、关于平衡控制系统二、实验效果三、硬件选择1、H7P20N0L176-M2H12、MPU6050 四、理论简述五、程序设计1、Cordic算法2、MPU6050采集数据3、fir&iir滤波4、姿态解算 六、资源消耗&工程获取七、总结 前言 很久之前&#xff0c;就想用纯FPGA做一套控制系统。可…

C++二维数组(2)

图形相似度 题目描述&#xff1a; 给出两幅相同大小的黑白图像&#xff08;用0-1矩阵&#xff09;表示&#xff0c;求它们的相似度。 说明&#xff1a;若两幅图像在相同位置上的像素点颜色相同&#xff0c;则称它们在该位置具有相同的像素点。 两幅图像的相似度定义为相同像素…

通过socketpair+select实现线程同步的用法代码

1&#xff0c;socketpair详细用法说明 socketpair()是一个Unix/Linux系统调用&#xff0c;用于创建一个本地端对&#xff08;socket pair&#xff09;。它创建两个已连接的socket描述符&#xff0c;用于在同一进程中的两个不同线程之间进行通信。 以下是socketpair()函数的详…

飞天使-linux操作的一些技巧与知识点6-ansible结合jinja2使用,可规范化进行自动化管控

文章目录 在议playbook虚拟环境中安装ansibleplaybook 结合变量的一些演示普通的vars_files 变量&#xff0c;在同级目录创建目录使用host_vars 定义变量group_vars定义变量根据不同系统操作不同版本传递多个外置变量举例几个不同的示例factswhenloophandlers 与 notifytags 任…

个人养老金知多少?

个人养老金政策你了解吗&#xff1f;税优政策你知道吗&#xff1f;你会计算能退多少税吗&#xff1f;… 点这里看一看

橘子学K8S01之容器中所谓的隔离

我们一直都在说容器就是一个沙盒&#xff0c;沙盒技术顾名思义就是像一个集装箱一样&#xff0c;把应用(服务&#xff0c;进程之类的)装起来的技术&#xff0c;这样每个进程在自己的沙盒中和其他的沙盒隔离开来&#xff0c;每个沙盒之间存在一个边界使得他们互不干扰&#xff0…

NFTScan 获得比特丛林 (BitJungle) 公司战略投资

近日&#xff0c;NFT 数据基础设施服务商 NFTScan 获得知名区块链安全公司比特丛林 (BitJungle) 战略投资。未来&#xff0c;双方将在链上数据和区块链安全领域展开战略合作&#xff0c;高效联动&#xff0c;让区块链大数据发挥更大价值。 关于 BitJungle 比特丛林 (BitJungle…

删除指定文件夹下的所有文件

要删除指定文件所在的文件夹下的所有文件&#xff08;不包括文件夹本身&#xff09;&#xff0c;你可以使用Python的os模块和os.path模块。下面是一个示例代码&#xff0c;演示如何删除文件夹下的所有文件&#xff0c;但保留文件夹本身&#xff1a; import osdef delete_files…

鸿鹄云商:Java商城引领商业模式的潮流,免费搭建多种商城模式

java SpringCloud版本b2b2c鸿鹄云商平台全套解决方案 使用技术&#xff1a; Spring CloudSpring BootMybatis微服务服务监控可视化运营 B2B2C平台&#xff1a; 平台管理端(包含自营) 商家平台端(多商户入驻) PC买家端、手机wap/公众号买家端 微服务&#xff08;30个通用…

idea插件开发报错: ZipException opening “slf4j.jar“: zip END header not found

错误信息 E:\idea-workspace\#idea-plugin\JSON2Object\src\main\java\com\hgy\plugin\json2object\GenerateAction.java:1: 错误: 无法访问com.hgy.plugin.json2object package com.hgy.plugin.json2object; ^ZipException opening "slf4j.jar": zip END header no…

在 Python 中,assert 是一个断言语句

在 Python 中&#xff0c;assert 是一个断言语句&#xff0c;用于测试代码中的条件是否为真。它的语法如下&#xff1a; assert condition, message其中&#xff0c;condition 是要测试的条件&#xff0c;如果条件为真&#xff08;True&#xff09;&#xff0c;则程序继续执行…

湖南开放大学形成性考核 平时作业 参考试题

试卷代号&#xff1a;1292 企业集团财务管理 参考试题&#xff08;开卷&#xff09; 一、单项选择题&#xff08;将正确答案的字母序号填入括号内。每小题2分&#xff0c;共20分&#xff09; 1.当投资企业拥有被投资企业有表决权的资本比例超过50%以上时&#xff0c;母公司…

MyBatisPlus常用注解

TableName 描述&#xff1a;表名注解&#xff0c;标识实体类对应的表 使用位置&#xff1a;实体类 MyBatis-Plus在确定操作的表时&#xff0c;由BaseMapper的泛型决定&#xff0c;即实体类型决定&#xff0c;且默认操作的表名和实体类型的类名一致。 此时可通过TableName注解直…

用23种设计模式打造一个cocos creator的游戏框架----(十六)亨元模式

1、模式标准 模式名称&#xff1a;亨元模式 模式分类&#xff1a;结构型 模式意图&#xff1a;运用共享技术有效地支持大量细粒度的对象 结构图&#xff1a; 适用于&#xff1a; 1、一个应用程序使用了大量的对象. 2、完全由于使用大量的对象&#xff0c;造成很大的存储开…