vue后台管理之动态加载路由的方法


Posted in Javascript onAugust 13, 2018

在这里我们将会实现一个vue动态路由的案列,当用户登陆成功后,根据用户的角色,拿到他对应的菜单信息,并将它动态的载入到我们的路由中。

我们的通用的后台管理系统中,我们会根据权限的粗细不同,会对每个角色每个权限每个资源进行控制。同样的我们也需要实现一个这样的功能。 这篇文章我将主要讲vue端的实现,关于后台接口我就不会涉及,当我接触的时候我们的后台接口是springcloud实现。

一、思路

在vue-router对象中首先初始化公共路由,比如(404,login)等,然后在用户登陆成功,根据用户的角色信息,获取对应权限菜单信息menuList,并将后台返回的menuList转换成我们需要的router数据结构,然后通过vue-router2.2新添的router.addRouter(routes)方法,同时我们可以将转后的路由信息保存于vuex,这样我们可以在我们的SideBar组件中获取我们的全部路由信息,并且渲染我们的左侧菜单栏,让动态路由实现。

二、实现

1、公共路由定义

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)
/* Layout */
import Layout from '../views/layout/Layout'

export const constantRouterMap = [
 { path: '/login', component: () => import('@/views/login/index'), hidden: true },
 { path: '/404', component: () => import('@/views/404'), hidden: true },

 {
  path: '/',
  component: Layout,
  redirect: '/dashboard',
  name: 'Dashboard',
  hidden: true,
  children: [{
   path: 'dashboard',
   component: () => import('@/views/dashboard/index')
  }]
 },
]
export default new Router({
 scrollBehavior: () => ({ y: 0 }),
 routes: constantRouterMap
})

2、获取菜单信息

router.beforeEach((to, from, next) => {
 NProgress.start() // start progress bar
 if (getToken()) { // determine if there has token
  /* has token*/
  if (to.path === '/login') {
   next({ path: '/' })
   NProgress.done() // if current page is dashboard will not trigger afterEach hook, so manually handle it
  } else {
   if (store.getters.roles.length === 0) { // 判断当前用户是否已拉取完user_info信息
    store.dispatch('GetInfo').then(res => { // 拉取user_info
     const roles = res.roles
     store.dispatch("GetMenu").then(data => {
      initMenu(router, data);
     });
     next()
    }).catch((err) => {
     store.dispatch('FedLogOut').then(() => {
      Message.error(err || 'Verification failed, please login again')
      next({ path: '/' })
     })
    })
   } else {
    next()
   }
  }
 } else {
  /* has no token*/
  if (whiteList.indexOf(to.path) !== -1) { // 在免登录白名单,直接进入
   next()
  } else {
   next('/login') // 否则全部重定向到登录页
   NProgress.done() // if current page is login will not trigger afterEach hook, so manually handle it
  }
 }
})

router.afterEach(() => {
 NProgress.done() // finish progress bar
})

在这里 我们通过在router的beforeEach钩子函数 判断用户是否已经获得角色信息,如果没有,则请求后台获取对应的角色信息,然后通过角色信息再次请求获取对应的菜单列表,获取到菜单列表,然后去格式化菜单列表,使其转换成router数组的结构。

3、动态加载路由

import store from '../store'

export const initMenu = (router, menu) => {
 if (menu.length === 0) {
  return
 }
 let menus = formatRoutes(menu);
 // 最后添加
 let unfound = { path: '*', redirect: '/404', hidden: true }
 menus.push(unfound)
 router.addRoutes(menus)
 store.commit('ADD_ROUTERS',menus)
}

export const formatRoutes = (aMenu) => {
 const aRouter = []
 aMenu.forEach(oMenu => {
  const {
   path,
   component,
   name,
   icon,
   childrens
  } = oMenu
  if (!validatenull(component)) {
   let filePath;
   const oRouter = {
    path: path,
    component(resolve) {
     let componentPath = ''
     if (component === 'Layout') {
      require(['../views/layout/Layout'], resolve)
      return
     } else {
      componentPath = component
     }
     require([`../${componentPath}.vue`], resolve)
    },
    name: name,
    icon: icon,
    children: validatenull(childrens) ? [] : formatRoutes(childrens)
   }
   aRouter.push(oRouter)
  }

 })
 return aRouter
}

在这里我们把menList转换成routerList因为我们后台返回的数据不是规范的router结构,所以这里需要我们处理一下,如果你们后台返回规范的就不需要处理,然后通过router.addRoutes把后台返回的加入到我们的路由中,并且将其保存在我们的vuex中,需要主要的 如果404组件一定要放在动态路由在后载入。

4、渲染菜单

其实这里已经不属于我们的所讲的重点,在这里只需要取出上一步存在vuex中的路由信息,并且将其渲染成我们的左侧菜单栏就可以。在这里我们使用了element-ui。

<template>
 <el-scrollbar wrapClass="scrollbar-wrapper">
  <el-menu
   mode="vertical"
   :show-timeout="200"
   :default-active="$route.path"
   :collapse="isCollapse"
   background-color="#304156"
   text-color="#bfcbd9"
   active-text-color="#409EFF"
  >
   <sidebar-item v-for="route in permission_routers" :key="route.name" :item="route" :base-path="route.path"></sidebar-item>
  </el-menu>
 </el-scrollbar>
</template>

<script>
import { mapGetters } from 'vuex'
import SidebarItem from './SidebarItem'
import { validatenull } from "@/utils/validate";
import { initMenu } from "@/utils/util";

export default {
 components: { SidebarItem },
 created() {
 },
 computed: {
  ...mapGetters([
   'permission_routers',
   'sidebar',
   'addRouters'
  ]),
  isCollapse() {
   return !this.sidebar.opened
  }
 }
}
</script>

就这样我们动态加载路由就是实现了,是不是很简单,关键点就是router.addRoute方法。下面我就说一下防踩坑点。

三、防坑

1、关于加载菜单信息的时机

在此之前我将第二步获取菜单信息放在我的SideBar组件的create函数中,当时我发现也没有什么问题。登录跳转到home界面 左侧菜单也成功渲染,点击菜单进入我们动态加载的路由界面,也没问题。但是当我点击刷新的时候问题来。页面空白 控制台也不报错。当时我就蒙蔽了,什么情况,不是好好的嘛?如果大家也遇到这种这时候大家不要着急,冷静的分析整个流程,就会发现问题的所在。

1、登陆成功跳转home界面,home组件是公共路由,存在的没问题。

2、这时候 sidebar组件create钩子触发,成功获取菜单列表

3、菜单列表转成路由数组,并且加载到router实例中和vuex中

4、sidebar从vuex获取到路由数组渲染菜单 进入我们动态加载页面中,显示正常,这一切看起来没什么问题

5、点击浏览器的刷新按钮、或者F5,页面空白。

原因: 第五步中我们我们浏览器刷新,在spa应用整个vue实例会重新加载,也是说我的vue-router会重新初始化,那么我们之前的动态addRoute就不存在了,但是我们此时访问一个不存在的页面,所以我们的sidebar组件也就不会被访问,那么也无法获取菜单信息,就导致页面空白。所以我们需要把加载菜单信息这一步放在router的全局守卫beforeEach中就可以了。

2、关于404组件的位置

大家可以看到

export const initMenu = (router, menu) => {
 if (menu.length === 0) {
  return
 }
 let menus = formatRoutes(menu);
 // 最后添加
 let unfound = { path: '*', redirect: '/404', hidden: true }
 menus.push(unfound)
 router.addRoutes(menus)
 store.commit('ADD_ROUTERS',menus)
}

我强调了 404组件一定要放在动态路由组件的最后,不然你刷新动态加载的页面,会跳转到404页面的。

四、效果图

vue后台管理之动态加载路由的方法

动态路由

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
学习jquery之一
Apr 27 Javascript
javascript下给元素添加事件的方法与代码
Aug 13 Javascript
jQuery的.live()和.die() 使用介绍
Sep 10 Javascript
JavaScript中的console.trace()函数介绍
Dec 29 Javascript
详解AngularJS中的http拦截
Feb 09 Javascript
jQuery CSS3自定义美化Checkbox实现代码
May 12 Javascript
js绘制购物车抛物线动画
Nov 18 Javascript
JS使用面向对象技术实现的tab选项卡效果示例
Feb 28 Javascript
基于Node.js的WebSocket通信实现
Mar 11 Javascript
jQuery Position方法使用和兼容性
Aug 23 jQuery
Node.js dgram模块实现UDP通信示例代码
Sep 26 Javascript
js实现百度淘宝搜索功能
Feb 17 Javascript
jQuery中$原理实例分析
Aug 13 #jQuery
Angular服务Request异步请求的实例讲解
Aug 13 #Javascript
微信小程序中使用wxss加载图片并实现动画效果
Aug 13 #Javascript
深入浅析angular和vue还有jquery的区别
Aug 13 #jQuery
Angular异步变同步处理方法
Aug 13 #Javascript
利用JS实现一个同Excel表现的智能填充算法
Aug 13 #Javascript
Vue自定义弹窗指令的实现代码
Aug 13 #Javascript
You might like
IIS安装Apache伪静态插件的具体操作图文
2013/07/01 PHP
zf框架db类的分页示例分享
2014/03/14 PHP
php使用include 和require引入文件的区别
2017/02/16 PHP
php实现生成code128条形码的方法详解
2017/07/19 PHP
浅谈Laravel队列实现原理解决问题记录
2017/08/19 PHP
PHPExcel实现表格导出功能示例【带有多个工作sheet】
2018/06/13 PHP
用js实现的页面关键字密度查询代码
2007/12/27 Javascript
jquery 学习笔记一
2010/04/07 Javascript
javascript放大镜效果的简单实现
2013/12/09 Javascript
javascript(js)的小数点乘法除法问题详解
2014/03/07 Javascript
nodejs 中模拟实现 emmiter 自定义事件
2016/02/22 NodeJs
JS中使用apply方法通过不同数量的参数调用函数的方法
2016/05/31 Javascript
JS产生随机数的几个用法详解
2016/06/22 Javascript
JavaScript实现类似拉勾网的鼠标移入移出效果
2016/10/27 Javascript
[03:18]DOTA2亚洲邀请赛小组赛第一日 RECAP赛事回顾
2015/01/30 DOTA
[01:32]DOTA2 2015国际邀请赛中国区预选赛第四日战报
2015/05/29 DOTA
[59:00]OG vs TNC 2018国际邀请赛小组赛BO2 第一场 8.19
2018/08/21 DOTA
python基于xmlrpc实现二进制文件传输的方法
2015/06/02 Python
Python利用pandas处理Excel数据的应用详解
2019/06/18 Python
python正则爬取某段子网站前20页段子(request库)过程解析
2019/08/10 Python
python调用函数、类和文件操作简单实例总结
2019/11/29 Python
Python logging模块进行封装实现原理解析
2020/08/07 Python
韩国知名的家庭购物网站:CJmall
2016/08/01 全球购物
天猫精选:上天猫,就够了
2016/09/21 全球购物
如何转换一个字符串到enum值
2014/04/12 面试题
动物学专业毕业生求职信
2013/10/11 职场文书
给幼儿园老师的表扬信
2014/01/19 职场文书
2014年幼儿园元旦活动方案
2014/02/13 职场文书
气象学专业个人求职信
2014/04/22 职场文书
记账会计岗位职责
2014/06/16 职场文书
计算机相关专业自荐信
2014/07/02 职场文书
领导班子群众路线与四风问题对照检查材料思想汇报
2014/10/11 职场文书
2014年终个人工作总结
2014/11/07 职场文书
寻衅滋事罪辩护词
2015/05/21 职场文书
民政局2016年“六一”儿童节慰问活动总结
2016/04/06 职场文书
Vue vee-validate插件的简单使用
2021/06/22 Vue.js