vue2项目动态路由,菜单管理

不同的用户,访问管理系统的时候,是具有不同的权限,有些页面是可以访问一些页面不能访问。同时不同用户看到的系统菜单也有可能是不同的。

实现方式是前后端一起控制。 前端把所有的路由全部都列举出来,但是会给每个路由加一个权限的字段,来和后端给的数据做匹配。从而实现A用户登录后,访问A用户能访问的页面,展示A用户的对应的系统菜单。B用户对应B的。

代码实现:

1、配置路由文件

router 文件夹下,建一个routerData.js文件,存放路由数据。

commonRoutes 表示公共路由,和用户权限无关,每个用户都能访问的路由,一般放登录页面。

dynamicRoutes表示动态路由,前端写所有的页面路由在里面,后面改路由会和后端给的数据进行匹配。

js 复制代码
import layout from '@/layout/index'

export const commonRoutes = [
  {
    path: '/login',
    name: 'login',
    component: () => import('@/views/Login.vue')
  },
]

const dynamicRoutes = [
  {
    path: '/',
    name: 'layout',
    component: layout,
    meta: {
      title: '-',
      permission: [2, 6, 7, 8, 9] //页面权限: 2:出单员、 6:管理岗 (管理权限)、 7:跟单员、 8:管理+出单员、 9:管理+跟单  
    },
    children: [
      {
        path: '/system-set',
        name: 'systemSet',
        meta: {
          title: '系统设置',
          icon: 'li-icon-basic-settings',
          permission: [2, 6, 7, 8, 9]
        },
        component: () => import('@/views/system-set'),
        children: [
          {
            path: '/system-set/account-manage',
            name: 'accountManage',
            meta: {
              title: '账号管理',
              hidden: true,
              permission: [6]
            },
            component: () => import('@/views/system-set/account-manage'),
          },
          {
            path: '/system-set/person-center',
            name: 'personCenter',
            meta: {
              title: '个人中心',
              permission: [2, 6, 7, 8, 9]
            },
            component: () => import('@/views/system-set/person-center'),
          },
        ]
      }
    ],
  }
]

export default dynamicRoutes

router 文件夹下的入口文件 index.js

js 复制代码
//导入必要
import Vue from 'vue'
import VueRouter from 'vue-router'

//export defalut 导出的话就不需要{}符号
import dynamicRoutes from "./routerData.js"; 
//export 普通导出 需要使用{} 来表明导出的是哪个
import { commonRoutes } from "./routerData.js"; 

//挂载路由
Vue.use(VueRouter) , 才能使用

//匹配动态路由的方法
/**
dynamicRoutesVal:前端完整的动态路由
roleType:用户的权限角色
filter:不会改变原数组,会生成一个新数组,不过也是浅拷贝。(符合条件的被放进新数组里去)
*/
export const permissionRouter = function(dynamicRoutesVal, roleType) {
  return dynamicRoutesVal?.filter(item => {
    if(item.children){
    //疑问?这边有三级路由时,子路由会不会受影响,动态减少
      item.children = permissionRouter(item.children, roleType)
    }
    return item.meta.permission?.includes(roleType)
  })
}

const router = new VueRouter({
  scrollBehavior: () => ({ y: 0 }),
  mode: 'history',
  base: process.env.BASE_URL,
  routes: commonRoutes
})

export function resetRouter() {
  router.matcher = router.matcher // reset router
}

export default router

2、路由权限文件

1、在 utils 文件夹下创建一个 路由权限文件permission.js

js 复制代码
import store from "@/store/index.js";
import dynamicRoutes from "@/router/routerData";
import router, {permissionRouter} from '@/router/index'
import { Loading,Message } from '@chehejia/liui';

router.beforeEach((to, from, next) => {
  // 检查用户是否已登录
  const hasToken = store.state.userToken;

  // 如果用户已登录,则允许访问目标页面
  if (hasToken) {
    if(to.path === '/login') {
      next()
    }else {
      const routeList = store.state.addRouters || []
      if(routeList.length > 0) {
        next()
      }else {
        const permissionRouterList = permissionRouter(dynamicRoutes, store.state.LiUser.roleCode)
        permissionRouterList.map(item => {
          router.addRoute(item)
        })
        store.commit('SET_ROUTERS', permissionRouterList); 
        next({...to, replace: true}) // hack方法 确保addRoutes已完成 ,set the replace: true so the navigation will not leave
      }
    }
  } else {
    if(to.path === '/login'){
      next()
    }else{
      // 如果用户未登录,则重定向到登录页面
      next("/login");
    }
  }
});

3、使用路由

在项目入口文件,main.js中

js 复制代码
//导入路由文件
import router from './router'
import './utils/permission.js' 

//创建一个vue实例,并使用配置的路由
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')

4、登录成功拿到数据,加上该用户权限的动态路由

js 复制代码
import dynamicRoutes from "@/router/routerData";
import router, {permissionRouter} from '@/router/index'

 // 生成动态路由
 const permissionRouterList = permissionRouter(dynamicRoutes, this.$store.state.LiUser.roleCode)
  permissionRouterList.map(item => {
    router.addRoute(item)
  })
  this.$store.commit('SET_ROUTERS', permissionRouterList);
js 复制代码
mutations: {
    SET_ROUTERS: (state,val) => {
      state.addRouters = val
      state.routers = commonRoutes.concat(val);
      storage.set('addRouters', val)
      storage.set('routers', commonRoutes.concat(val))
    },
 }

5、问题: 页面刷新后出现白屏的问题,(你新开一个窗口,输入刚才展示的地址,也是属于页面刷新)。 本质:刷新vue实例重构,路由没有被加上,找不到对应路由,所以页面空白。

问题详细说明: 此次使用loacalStorage实现持续话存储,但这个页面刷新出现白屏没有任何关系。 页面刷新vue实例会被重新构建,你用loacalStorage实现持续话存储,vuex数据问题是可以得到解决。但是vue实例重构,vue-router也会重构,所以动态匹配的路由没有被加到路由上去,所以所访问的url的路由找不到,导致页面空白。

解决方法:

在页面刷新后,重新在上匹配上的路由。 App.vue主组件,每次vue实例创建都会创建App.vue组件。所以我在该组件的created生命周期是重新加上了动态路由,代码如下:

js 复制代码
<script>
  import store from "@/store/index.js";
  import dynamicRoutes from "@/router/routerData";
  import router, {permissionRouter} from '@/router/index'
  export default {
    name: 'App',
    data() {  
      return {}  
    },
    created() {
      // 页面刷新 生成动态路由
      console.log('APP-created');
      if (store.state.userToken && store.state.LiUser.roleCode) {
        // 生成动态路由
        const permissionRouterList = permissionRouter(dynamicRoutes, store.state.LiUser.roleCode)
        permissionRouterList.map(item => {
          router.addRoute(item)
        })
        store.commit('SET_ROUTERS', permissionRouterList); 

      }
    }
  }
</script>
相关推荐
前端摸鱼匠28 分钟前
Vue 3 的v-bind合并行为:讲解v-bind与普通属性合并的规则
前端·javascript·vue.js·前端框架·ecmascript
REDcker1 小时前
浏览器端Web程序性能分析与优化实战 DevTools指标与工程清单
开发语言·前端·javascript·vue·ecmascript·php·js
donecoding2 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马2 小时前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren2 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川3 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
jinanwuhuaguo3 小时前
(第二十九篇)OpenClaw 实时与具身的跃迁——从异步孤岛到数字世界的“原住民”
前端·网络·人工智能·重构·openclaw
广州华水科技3 小时前
深度测评2026年单北斗GNSS位移监测系统推荐,与高口碑变形监测设备一同引领行业新风尚
前端
Alice-YUE4 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript