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>
相关推荐
zhu128930355623 分钟前
用Rust和WebAssembly打造轻量级前端加密工具
前端·rust·wasm
@PHARAOH1 小时前
WHAT - Electron 系列(一)
前端·javascript·electron
半句唐诗1 小时前
设计与实现高性能安全TOKEN系统
前端·网络·安全
小满zs1 小时前
React-router v7 第二章(路由模式)
前端·react.js
yanxy5122 小时前
【TS学习】(18)分发逆变推断
前端·学习·typescript
大莲芒2 小时前
react 15-16-17-18各版本的核心区别、底层原理及演进逻辑的深度解析--react18
前端·javascript·react.js
Hellyc2 小时前
SpringMVC响应数据:页面跳转与回写数据
java·前端·学习
CaveShao2 小时前
前端开发中常见的 SEO 优化
前端·seo
Hyyy2 小时前
ElementPlus按需加载 + 配置中文避坑(干掉1MB冗余代码)
前端·javascript·面试
Summer_Xu3 小时前
模拟 Koa 中间件机制与洋葱模型
前端·设计模式·node.js