[VUE学习]权限管理系统前端vue实现9-动态路由,动态标签页,动态面包屑

旧城等待, 2024-04-20 22:13 178阅读 0赞

1.动态路由

1.因为我们左侧权限菜单是根据不同用户显示不一样的 所以我们需要使用动态路由 来动态生成右侧路由信息

在总体布局页面添加router

  • <router-view> 是 Vue Router 提供的组件,用于动态展示匹配到的路由组件内容。
  • 通过在合适的位置放置 <router-view>,你可以根据路由路径动态地渲染对应的组件内容。

ceecd83688dc4c958fe2a9e4ea9559ab.png

2.router里面需要添加children

因为我们是多级页面 之后动态路由也是多级的 如果这里不提前写children 之后动态生成的时候找不到Children

f8c9339c4f754b4ab15c590dd8db0bb9.png

3.做动态路由是否生成判断 尽量减少生成次数

1.在store里面添加全局状态

d07d85331bea4149b6f0c825cff2a1d9.png

4.permission.js

  1. router.beforeEach((to,from,next)=>{
  2. const whiteList=['/login'] // 白名单
  3. let token=store.getters.GET_TOKEN;
  4. let hasRoutes = store.state.hasRoutes;
  5. let menuList = store.getters.GET_MENULIST
  6. if(token){
  7. if(!hasRoutes){
  8. bindRoute(menuList);
  9. store.commit("SER_ROUTES_STATE",true)
  10. //注意这一行代码 在这一篇文章 详细解释了 如不过写会刷新白屏
  11. next({ ...to, replace: true })
  12. }else{
  13. next();
  14. }
  15. }else{
  16. if(whiteList.includes(to.path)){
  17. next();
  18. }else{
  19. next("/login");
  20. }
  21. }
  22. })
  23. const bindRoute=(menuList)=>{
  24. let newRoutes = router.options.routes;
  25. menuList.forEach(menu=>{
  26. if(menu.children){
  27. menu.children.forEach(m=>{
  28. let route = menuToRoute(m,menu.name)
  29. if(route){
  30. newRoutes[0].children.push(route);
  31. }
  32. })
  33. }
  34. })
  35. //重新添加到路由
  36. newRoutes.forEach(route=>{
  37. router.addRoute(route)
  38. })
  39. }
  40. const menuToRoute=(menu,parentName)=>{
  41. if(!menu.component){
  42. return null;
  43. }else{
  44. let route={
  45. name:menu.name,
  46. path:menu.path,
  47. meta:{
  48. parentName:parentName
  49. }
  50. }
  51. route.component=()=>import('@/views/'+menu.component+'.vue')
  52. return route
  53. }
  54. }

1.menuList是我们在登录时候得到的 树形结构 表结构0d9c41195b4b4688a5b420b2561bdad8.png

2.menuToRounte是动态生成路由 我们传入menu和父级名字(因为父级名字之后会用到)

生成route对象 包括 name path 和父级名字

component对应着目录结构b0f4a5bab0aa4b74a99bc314719a7eac.png

3.生成之后 然后把他们添加到路由里面

  1. bindRoute 函数用于将菜单列表转换为路由配置,并添加到路由实例中。它遍历菜单列表,并根据每个菜单项生成对应的路由配置,然后将这些路由配置添加到 newRoutes 数组中。最后,通过 router.addRoute 方法将所有路由配置添加到路由实例中。
  2. menuToRoute 函数用于将菜单项转换为路由配置。如果菜单项没有指定组件,则返回 null;否则,生成一个包含菜单名、路径和父菜单名的路由配置对象,并设置组件为异步加载形式。

2.动态标签页

6fe32abd37d34ed9978abf98700f4d87.png

1.store里面添加标签页数组 一个是当前标签页 一个是全部打开的

  1. state: {
  2. hasRoutes: false,
  3. editableTabsValue: '/index',
  4. editableTabs: [
  5. {
  6. title: '首页',
  7. name: '/index'
  8. }
  9. ]
  10. },
  11. ADD_TABS: (state, tab) => {
  12. if (state.editableTabs.findIndex(e => e.name == tab.path) === -1) {
  13. state.editableTabs.push({
  14. title: tab.name,
  15. name: tab.path
  16. })
  17. }
  18. state.editableTabsValue = tab.path
  19. },
  20. RESET_TABS: (state) => {
  21. state.editableTabsValue = '/index',
  22. state.editableTabs = [
  23. {
  24. title: '首页',
  25. name: '/index'
  26. }
  27. ]
  28. },

安全退出时候 调用RESET_TABS这个方法 清空

  1. if(result.data.code===200){
  2. store.commit("SER_ROUTES_STATE",false)
  3. store.commit("RESET_TABS")
  4. store.dispatch('logout')
  5. }

在menuIndex里面添加 click点击事件

57eea879a9f34dbd87842f8f42dbb289.png

2.tabIndex具体实现

1.关联store里面数据

涉及到路由 使用useRouter

  1. const router = useRouter();
  2. const editableTabsValue = ref(store.state.editableTabsValue)
  3. const editableTabs = ref(store.state.editableTabs)

因为我们关联的是store里面的数据 所以当我们store里面数据发生更改之后 页面并没有发生改变 所以我们需要对数据进行监听 当发生更改之后 重新赋值

  1. <template>
  2. <!-- 选中-->
  3. <el-tabs
  4. v-model="editableTabsValue"
  5. type="card"
  6. class="demo-tabs"
  7. closable
  8. @tab-remove="removeTab"
  9. @tab-click="clickTab"
  10. >
  11. <!-- 所有tab-->
  12. <el-tab-pane
  13. v-for="item in editableTabs"
  14. :key="item.name"
  15. :label="item.title"
  16. :name="item.name"
  17. >
  18. {
  19. { item.content }}
  20. </el-tab-pane>
  21. </el-tabs>
  22. </template>
  23. <script setup>
  24. import {ref, watch} from 'vue'
  25. import store from '@/store'
  26. import {useRouter} from "vue-router";
  27. const router = useRouter();
  28. const editableTabsValue = ref(store.state.editableTabsValue)
  29. const editableTabs = ref(store.state.editableTabs)
  30. const removeTab = (targetName) => {
  31. const tabs = editableTabs.value
  32. let activeName = editableTabsValue.value
  33. // 这里是Path 使得无法删除首页
  34. if(targetName==='/index'){
  35. return
  36. }
  37. if (activeName === targetName) {
  38. tabs.forEach((tab, index) => {
  39. if (tab.name === targetName) {
  40. const nextTab = tabs[index + 1] || tabs[index - 1]
  41. if (nextTab) {
  42. activeName = nextTab.name
  43. }
  44. }
  45. })
  46. }
  47. editableTabsValue.value = activeName
  48. editableTabs.value = tabs.filter((tab) => tab.name !== targetName)
  49. store.state.editableTabsValue = editableTabsValue.value
  50. store.state.editableTabs=editableTabs.value
  51. // 这个获取的是path
  52. router.push({path:activeName})
  53. }
  54. const refreshTabs =()=>{
  55. editableTabsValue.value=store.state.editableTabsValue;
  56. editableTabs.value=store.state.editableTabs;
  57. }
  58. // 可以拿到标签名称 可以根据Name 也可以根据path
  59. const clickTab =(target)=>{
  60. router.push({name:target.props.label})
  61. }
  62. // 监听变化
  63. watch(store.state,()=>{
  64. refreshTabs();
  65. },{deep:true,immediate:true})
  66. // 深度监听
  67. </script>
  68. <style>
  69. .demo-tabs > .el-tabs__content {
  70. padding: 32px;
  71. color: #6b778c;
  72. font-size: 32px;
  73. font-weight: 600;
  74. }
  75. .el-main{
  76. padding:0px;
  77. }
  78. .el-tabs--card>.el-tabs__header .el-tabs__item.is-active{
  79. background-color: lightgray;
  80. }
  81. .el-tabs{
  82. height:45px
  83. }
  84. </style>

3.动态面包屑实现

面包屑fc5e18c677844369811ec7dfc6f68554.png

这里就使用到了我们前面提到的parentName

三个if

如果是父级名字 并且index大于一 显示并且加 / 系统管理/

如果是最后一个直接显示 角色管理

  1. <template>
  2. <el-icon><HomeFilled /></el-icon>
  3. <el-breadcrumb separator="/">
  4. <el-breadcrumb-item v-for="(item,index) in breadcrumbList" :key="index">
  5. <span class="root" v-if="parentName && index>0">{
  6. {parentName}} / </span>
  7. <span class="leaf" v-if="index==breadcrumbList.length-1">{
  8. {item.name}}</span>
  9. <span class="root" v-else>{
  10. {item.name}}</span>
  11. </el-breadcrumb-item>
  12. </el-breadcrumb>
  13. </template>
  14. <script setup>
  15. import { ref,watch } from 'vue'
  16. import {HomeFilled} from '@element-plus/icons-vue'
  17. import {useRoute} from 'vue-router'
  18. import store from "@/store";
  19. const route=useRoute();
  20. const breadcrumbList=ref([]);
  21. const parentName=ref("")
  22. const initBreadcrumbList=()=>{
  23. breadcrumbList.value=route.matched;
  24. parentName.value=route.meta.parentName;
  25. }
  26. watch(route,()=>{
  27. initBreadcrumbList();
  28. },{deep:true,immediate:true})
  29. </script>
  30. <style lang="scss" scoped>
  31. .leaf{
  32. cursor:text;
  33. }
  34. .root{
  35. color:#666;
  36. font-weight:600;
  37. }
  38. </style>

4.路由与导航动态绑定实现

为了防止有人不点击 直接输入Url跳转 首先App.vue里面监听 然后添加标签页数据 此时标签页可以动态变化

  1. import { ref ,watch} from 'vue'
  2. import { useRoute,useRouter } from 'vue-router'
  3. const route=useRoute();
  4. const router=useRouter();
  5. const whitePath=['/login','/index','/']
  6. watch(route,(to,from)=>{
  7. console.log("to"+to.name)
  8. console.log(to.path)
  9. if (whitePath.indexOf(to.path)===-1) {
  10. console.log("to.path="+to.path)
  11. let obj = {
  12. name: to.name,
  13. path: to.path
  14. }
  15. store.commit("ADD_TABS", obj)
  16. }
  17. },{deep:true,immediate:true})

修改menu使得菜单栏也可以动态变化88feb019735b4c2cb1bac84d3c30699a.png

发表评论

表情:
评论列表 (有 0 条评论,178人围观)

还没有评论,来说两句吧...

相关阅读

    相关 vue 实现动态

    很多时候我们在项目的路由都是在前端配置好的 但是有的时候为了进行全面的权限控制,会需要后台给出路由表,前端再渲染。不用在前端配置。 下面主要讲一下思路 1、和后台小哥

    相关 Vue动态

    本文单纯的实现路由动态添加功能。 frist of all : 引入脚手架等一些网上都有教材的繁琐事,直到成功的打开页面,如下(自己做的一个登录页面) ![在这里插

    相关 Vue动态

    Vue动态路由 1、添加路由 2、在导航守卫中添加路由 3、删除路由 3.1 通过添加名称冲突的路由。 3.2 通过调用rou