视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
Vue动态路由的实现(后台传递路由,前端拿到并生成侧边栏)
2020-11-27 19:34:00 责编:小采
文档


前言

vue项目实现动态路由的方式大体可分为两种:
1.前端这边把路由写好,登录的时候根据用户的角色权限来动态展示路由,(前端控制路由)
详情可参阅花裤衩大佬的项目手把手...,我当时看这个项目看了好久才明白一点逻辑,
因为大神的动态路由那里有好多层判断,并且穿插各种vuex,把小白的我都快搞懵逼了,对我启发很大,也正是这篇文章,给我提供了很多逻辑
2.后台传来当前用户对应权限的路由表,前端通过调接口拿到后处理(后端处理路由)
这两种方法各有优点,效果都能实现,我们公司是通过第二中种方法实现的,原因就是公司项目里有一个专门的用户中心,里边逻辑很复杂,不好返给前端用户权限,担心路由放到前端
不安全(以上的话是公司的后台同学讲的),那好吧,抱着都试试、锻炼下自己能力的态度,
我们搞了第二种方法。

今天我们来讲讲用后台传递路由表实现动态路由的思路,因为公司的项目里路有部分用到了vuex,我就把路由部分脱离vuex整理了出来,让大家有个启发,并不是绝对的解决方案,只是思路
github:https://github.com/Mrblackant...
在线查看:http://an888.net/antRouter/#/...

思路整理

以下四步骤对应的代码都在下方会讲到,并且是对应的

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

代码

1.路由表

每个路由都使用到组件Layout,这个组件是整体的页面布局:左侧菜单列,右侧页面,所以children下边的第一级路由就是你自己的开发的页面,meta里包含着路由的名字,以及路由对应的icon;
因为可能会有多级菜单,所以会出现children下边嵌套children的情况;
路由是数组格式
"data": {
 "router": [
 {
 "path": "",
 "component": "Layout",
 "redirect": "dashboard",
 "children": [
 {
 "path": "dashboard",
 "component": "dashboard/index",
 "meta": {
 "title": "首页",
 "icon": "dashboard"
 }
 }
 ]
 },
 {
 "path": "/example",
 "component": "Layout",
 "redirect": "/example/table",
 "name": "Example",
 "meta": {
 "title": "案例",
 "icon": "example"
 },
 "children": [
 {
 "path": "table",
 "name": "Table",
 "component": "table/index",
 "meta": {
 "title": "表格",
 "icon": "table"
 }
 },
 {
 "path": "tree",
 "name": "Tree",
 "component": "tree/index",
 "meta": {
 "title": "树形菜单",
 "icon": "tree"
 }
 }
 ]
 },
 {
 "path": "/form",
 "component": "Layout",
 "children": [
 {
 "path": "index",
 "name": "Form",
 "component": "form/index",
 "meta": {
 "title": "表单",
 "icon": "form"
 }
 }
 ]
 },
 {
 "path": "*",
 "redirect": "/404",
 "hidden": true
 }
 ]
 }

2.将后端传回的"component": "Layout", 转为"component": Layout组件对象

因为有多级路由的出现,所以要写成遍历递归方法,确保把每个component转成对象,
因为后台传回的是字符串,所以要把加载组件的过程 封装成一个方法(此处参考花裤衩大神的解决方法),用这个方法在遍历中使用;详情查看项目里的router文件夹下的 _import_development.js和_import_production.js文件
Layout我放的目录跟其他文件的目录不一样,所以我在遍历里单独处理,各位小伙伴可自己调整哈
const _import = require('./router/_import_' + process.env.NODE_ENV)//获取组件的方法
import Layout from '@/views/layout' //Layout 是架构组件,不在后台返回,在文件里单独引入

function filterAsyncRouter(asyncRouterMap) { //遍历后台传来的路由字符串,转换为组件对象
 const accessedRouters = asyncRouterMap.filter(route => {
 if (route.component) {
 **加粗文字** if (route.component === 'Layout') {//Layout组件特殊处理
 route.component = Layout
 } else {
 route.component = _import(route.component)
 }
 }
 if (route.children && route.children.length) {
 route.children = filterAsyncRouter(route.children)
 }
 return true
 })

 return accessedRouters
}

3.使用beforeEach、addRoutes、localStorage来配合实现

beforeEach路由拦截,进入判断,如果发现本地没有路由数据,那就利用axios后台取一次,取完以后,利用localStorage存储起来,利用addRoutes动态添加路由,
ps:beforeEach好坏啊,一步小心就进入到了他的死循环,浏览器都tm崩了,得在一开始就加判断,拿到路由了,就直接next(),嘤嘤嘤
global.antRouter是为了传递数据给左侧菜单组件进行渲染
import axios from 'axios'

var getRouter //用来获取后台拿到的路由

router.beforeEach((to, from, next) => {
 if (!getRouter) {//不加这个判断,路由会陷入死循环
 if (!getObjArr('router')) {
 axios.get('https://www.easy-mock.com/mock/5a5da330d9b48c260cb42ca8/example/antrouter').then(res => {
 getRouter = res.data.data.router//后台拿到路由
 saveObjArr('router', getRouter) //存储路由到localStorage

 routerGo(to, next)//执行路由跳转方法
 })
 } else {//从localStorage拿到了路由
 getRouter = getObjArr('router')//拿到路由
 routerGo(to, next)
 }
 } else {
 next()
 }

})


function routerGo(to, next) {
 getRouter = filterAsyncRouter(getRouter) //过滤路由
 router.addRoutes(getRouter) //动态添加路由
 global.antRouter = getRouter //将路由数据传递给全局变量,做侧边栏菜单渲染工作
 next({ ...to, replace: true })
}

function saveObjArr(name, data) { //localStorage 存储数组对象的方法
 localStorage.setItem(name, JSON.stringify(data))
}

function getObjArr(name) { //localStorage 获取数组对象的方法
 return JSON.parse(window.localStorage.getItem(name));

}

4.拿到遍历好的路由,进行左侧菜单渲染

上边第三部会给 global.antRouter赋值,这是一个全局变量(可以用vuex替代),菜单那边拿到路由,进行渲染,这里又是参考了花裤衩大神的layout部分 ,这里我就不贴代码了

才疏学浅,希望大家多多指正,尤其对于路由拦截那部分,应该还有很多优化的地方,欢迎指正

下载本文
显示全文
专题