Vue实现动态路由(和面试官吹项目亮点)

您所在的位置:网站首页 前端动态化 Vue实现动态路由(和面试官吹项目亮点)

Vue实现动态路由(和面试官吹项目亮点)

2024-01-17 20:17| 来源: 网络整理| 查看: 265

前言 【音乐博客】上线啦!该动态路由已集成到【音乐博客】中,如有需要,可查看permission文件、vuex的store文件、router路由如果在面试中被面试官问到你项目中有什么亮点?你还在尴尬的低头说:就普通的增删改查显示页面吗?下面为大家展示在项目中使用动态路由成为一个小亮点!

此图是周末和女友逛K11觉得挺好看的,特意分享给各位猿友欣赏,希望我们可以玩转路由像小女孩一样,自由飞翔

动态路由 为什么使用动态路由?

很多时候我们在项目的路由都是在前端配置好的

但是有的时候为了进行全面的权限控制,会需要后台给出路由表,前端再渲染。不用在前端配置。 比如:根据用户的角色,登录进来显示不同的菜单

思路整理

菜单中有个角色管理,在页面上添加角色对应要显示的菜单,相当于把前端配置的路由表数据给后端存在数据库

拿到数据需要我们自己再处理

路由中的component后台是给不了的,这里我们只需要后台按照我们提供的前端component路径给数据,因为后端返回的component是字符串路径,而前端需要的是一个组件对象,写个方法循环加载,将字符串转换为组件对象 const loadViewsd = (view: any) => { return (resolve: any) => require( [`@/views/${view}.vue`], resolve )} 这样我们就拿到了最重要的数据,即component

利用vuerouter的beforeEacg、addRoutes来配合上边两步实现效果

把后台提供的数据处理成我们需要的路由表

添加到路由中 Router.addRoutes(路由数据)

大体步骤: 1.后端返回一个json格式的路由表2.因为后端传回来的是都是字符串格式的,但前端这里需要的是一个组件对象,写个方法遍历一下,将字符串转换为组件对象3.利用vue-router的beforeEach、addRoutes、vuex来配合上边两步实现效果4.左侧菜单拦截根据拿到转换好的路由列表进行展示拦截路由 -> 后端取到路由 -> 保存路由到vuex(用户登录进来只会从后端取一次,其余都从本地取,所以用户,只有退出在登录路由才会更新)

代码实现 新建一个router.js

里面就是我们的路由:每个路由都使用到组件Layout,这个组件是整体的页面布局:左侧菜单列,右侧页面,所以children下边的第一级路由就是你自己的开发的页面,meta里包含着路由的名字,以及路由对应的icon;

因为可能会有多级菜单,所以会出现children下边嵌套children的情况;

路由是数组格式

export const asyncRoutes = [ { path: '/permission', // // component: Layout, componentUrl: 'Layout', redirect: '/permission/directive', meta: { title: 'permission', icon: 'lock', alwaysShow: true // will always show the root menu } }, { path: '/sys', // // component: Layout, componentUrl: 'Layout', meta: { title: 'sys', icon: 'example', roles: ['admin'], // you can set roles in root nav alwaysShow: true, // will always show the root menu noCache: true }, children: [ { path: 'sys-user', // // component: () => import(/* webpackChunkName: "sys-user" */ '@/views/sys/sys-user.vue'), componentUrl: 'sys/sys-user', name: 'sysUser', meta: { title: 'sysUser', noCache: true } }, { path: 'sys-menu', // // component: () => import(/* webpackChunkName: "sys-menu" */ '@/views/sys/sys-menu.vue'), componentUrl: 'sys/sys-menu', name: 'sysMenu', meta: { title: 'sysMenu', noCache: true } }, { path: 'sys-role', // // component: () => import(/* webpackChunkName: "sys-role" */ '@/views/sys/sys-role.vue'), componentUrl: 'sys/sys-role', name: 'sysRole', meta: { title: 'sysRole', noCache: true } } ] } ]

基本路由表已经建立好了

我们在什么时候进行获取完整的路由表数据

这个时候我们就要想到路由钩子函数,当然是Router.beforeEach中做

router.beforeEach(async (to: Route, _: Route, next: any) => { // Start progress bar NProgress.start() // Determine whether the user has logged in if (UserModule.token) { if (to.path === '/login') { next({ path: '/' }) NProgress.done() } else { // 刚开始登录第一次进来,则进来 if (UserModule.roles.length === 0) { try { // Note: roles must be a object array! such as: ['admin'] or ['developer', 'editor'] await UserModule.GetUserInfo() // 获取用户角色 const roles = UserModule.roles // Generate accessible routes map based on role PermissionModule.GenerateRoutes(roles) // 将路由渲染到我们菜单上 // 若为空,则在去数据库读取渲染到菜单上 if (PermissionModule.dynamicRoutes.length === 0) { const { data } = await getSysRole({ page: 1, limit: 8, roleKey: roles[0] }) PermissionModule.dynamicRoutes = filterAsyncRouter(data.items[0].routes) } router.addRoutes(PermissionModule.dynamicRoutes) // 动态添加路由 next({ ...to, replace: true }) } catch (err) { // Remove token and redirect to login page UserModule.ResetToken() Message.error(err || 'Has Error') next(`/login?redirect=${to.path}`) NProgress.done() } } else { next() } } } else {} })

接下来我们在看看上述的PermissionModule.GenerateRoutes(roles)方法

这个方法是写在我们的vuex.store里面

@Action public async GenerateRoutes(roles: string[]) { let accessedRoutes if (roles.includes('admin')) { accessedRoutes = adminRoutes //就是我们上面定义的router.js } else { // 非管理员就后端读取数据库拿到用户的角色菜单 const {data} = await getSysRole({ page: 1, limit: 8, roleKey: roles[0] }) accessedRoutes = filterAsyncRouter(data.items[0].routes) } this.SET_ROUTES(accessedRoutes) } //遍历后台传来的路由字符串,转换为组件对象 export const filterAsyncRouter = (asyncRouterMap: any) =>{ const accessedRouters = asyncRouterMap.filter((route: any) => { if (route.componentUrl) { if (route.componentUrl === 'Layout') {//Layout组件特殊处理 route.component = Layout delete route.componentUrl // 这里有个坑,赋完值记得手动删除,因为打包编译失败,因为route里没有这个属性 } else { route.component = loadViewsd(route.componentUrl) delete route.componentUrl } } if (route.children && route.children.length) { route.children = filterAsyncRouter(route.children) } return route }) //全不匹配的情况下,返回404,路由按顺序从上到下,依次匹配。最后一个*能匹配全部, accessedRouters.push({ path: '*', redirect: '/404', meta: { hidden: true } }) return accessedRouters } // 字符串路径转为组件对象 // 将后端传回的"componentUrl": "Layout", 转为"component": Layout组件对象 export const loadViewsd = (view: any) => { return (resolve: any) => require([`@/views/${view}.vue`], resolve) } 动态路由遇到的坑 打包编译失败

项目开发dev中,动态路由显示正常,而到了打包build的时候,发现打包报错-serve:'vue-cli-service serve'

思考

一眼看过去以为是node-modules出了问题,结果重装了一下,结果无效

解决方案

这个报错一定是整体配置文件出了问题,检查一下vue.config.js文件是不是加了什么,可以注释掉试试看,因为我github上有build成功的这个项目;

所以我拉下来对比了之后,发现果然是动态路由这边的问题,可以看到下面是用了ts的定义类型,我们的路由定义了RouteConfig,而在vue-router源码中是没有componentUrl这个属性,然后我在开发的时候手动添加了,开发的时候是可以跑成功,但是打包的时候是编译失败的,因为他vue-router源码中是没有componentUrl这个属性;

后面我是怎么解决这个问题呢,我重新复制一份这个router.js文件,类型定义为any类型,就解决了(这个build err真的找了很久,没想到之前不小心改了他源码,感动啊终于找到问题所在)

import Router, { RouteConfig } from 'vue-router' export const asyncRoutes: RouteConfig[] = [ { path: '/permission', component: Layout, componentUrl: 'Layout', redirect: '/permission/directive', meta: { title: 'permission', icon: 'lock', alwaysShow: true // will always show the root menu }, children: [ { path: 'page', component: () => import(/* webpackChunkName: "permission-page" */ '@/views/permission/page.vue'), componentUrl: 'permission/page', name: 'PagePermission', meta: { title: 'pagePermission' } } ] } ] 动态路由加载报错

解决方案

在上面的filterAsyncRouter方法中将字符串转组件对象,component赋完值之后,要顺手把componentUrl给删除掉,和route类型有关,反正后续也不需要删除多余属性比较好

原文链接

juejin.cn/post/687234…

参考文档

Vue 动态路由的实现(后台传递路由,前端拿到并生成侧边栏)

vue 实现动态路由

本文使用 mdnice 排版



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3