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 相关文章推荐
JavaScript constructor和instanceof,JSOO中的一对欢喜冤家
May 25 Javascript
jQuery实现原理的模拟代码 -6 代码下载
Aug 16 Javascript
onkeydown事件解决按回车键直接提交数据的需求
Apr 11 Javascript
js实现的动画导航菜单效果代码
Sep 10 Javascript
js获取隐藏元素宽高的实现方法
May 19 Javascript
详解JavaScript中this关键字的用法
May 26 Javascript
Bootstrap弹出带合法性检查的登录框实例代码【推荐】
Jun 23 Javascript
判断输入的字符串是否是日期格式的简单方法
Jul 11 Javascript
js实现自定义进度条效果
Mar 15 Javascript
利用JQUERY实现多个AJAX请求等待的实例
Dec 14 jQuery
Angular 数据请求的实现方法
May 07 Javascript
JS如何实现基于websocket的多端桥接平台
May 14 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
php 动态多文件上传
2009/01/18 PHP
PHP文件打开、关闭、写入的判断与执行代码
2011/05/24 PHP
一个显示某段时间内每个月的方法 返回由这些月份组成的数组
2012/05/16 PHP
thinkphp实现数组分页示例
2014/04/13 PHP
magento后台无法登录解决办法的两种方法
2016/12/09 PHP
PHP用函数嵌入网站访问量计数器
2017/10/27 PHP
JavaScript 拖拉缩放效果
2008/12/10 Javascript
使用dynatrace-ajax跟踪JavaScript的性能
2010/04/12 Javascript
推荐10 款 SVG 动画的 JavaScript 库
2015/03/24 Javascript
jQuery层动画定位滑动效果的方法
2015/04/30 Javascript
jQuery表单验证功能实例
2015/08/28 Javascript
js强制把网址设为默认首页
2015/09/29 Javascript
自带气泡提示的vue校验插件(vue-verify-pop)
2017/04/07 Javascript
node.js中express-session配置项详解
2017/05/31 Javascript
jQuery实现的鼠标拖动浮层功能示例【拖动div等任何标签】
2018/12/29 jQuery
解决微信授权成功后点击按返回键出现空白页和报错的问题
2020/06/08 Javascript
[01:10:58]Spirit vs NB Supermajor小组赛 A组败者组决赛 BO3 第二场 6.2
2018/06/03 DOTA
python网络编程学习笔记(五):socket的一些补充
2014/06/09 Python
浅谈Python的垃圾回收机制
2016/12/17 Python
基于python 字符编码的理解
2017/09/02 Python
python按行读取文件,去掉每行的换行符\n的实例
2018/04/19 Python
python使用numpy读取、保存txt数据的实例
2018/10/14 Python
Pandas之Fillna填充缺失数据的方法
2019/06/25 Python
用Python画小女孩放风筝的示例
2019/11/23 Python
PyQT5 emit 和 connect的用法详解
2019/12/13 Python
MCAKE蛋糕官方网站:一直都是巴黎的味道
2018/02/06 全球购物
L’Artisan Parfumeur官网:法国香水品牌
2020/08/11 全球购物
5个HTML5的常用本地存储方式详解与介绍
2021/03/27 HTML / CSS
铣床操作工岗位职责
2014/06/13 职场文书
离婚协议书范本(通用篇)
2014/11/30 职场文书
2015年幼儿园元旦游艺活动策划书
2014/12/09 职场文书
大学学习委员竞选稿
2015/11/20 职场文书
2016高三毕业赠言寄语
2015/12/04 职场文书
高一作文之乐趣
2019/11/21 职场文书
导游词之南昌滕王阁
2019/11/29 职场文书
HashMap实现保存两个key相同的数据
2021/06/30 Java/Android