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 混淆加密收藏
Jan 16 Javascript
js汉字排序问题 支持中英文混排,兼容各浏览器,包括CHROME
Dec 20 Javascript
chrome下jq width()方法取值为0的解决方法
May 26 Javascript
Javascript动态引用CSS文件的2种方法介绍
Jun 06 Javascript
Js的Array数组对象详解
Feb 22 Javascript
JavaScript随机打乱数组顺序之随机洗牌算法
Aug 02 Javascript
Highcharts入门之简介
Aug 02 Javascript
canvas实现图像布局填充功能
Feb 06 Javascript
Layui选项卡制作历史浏览记录的方法
Sep 28 Javascript
解决vue v-for src 图片路径问题 404
Nov 12 Javascript
Angular封装表单控件及思想总结
Dec 11 Javascript
创建nuxt.js项目流程图解
Mar 13 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 daodb插入、更新与删除数据
2009/03/19 PHP
如何使用Gitblog和Markdown建自己的博客
2015/07/31 PHP
PHP迭代与递归实现无限级分类
2017/08/28 PHP
laravel 实现设置时区的简单方法
2019/10/10 PHP
IE浏览器打印的页眉页脚设置解决方法
2009/12/08 Javascript
javascript firefox 自动加载iframe 自动调整高宽示例
2013/08/27 Javascript
jQuery实现自动调整字体大小的方法
2015/06/15 Javascript
JS实现具备延时功能的滑动门菜单效果
2015/09/17 Javascript
jQuery xml字符串的解析、读取及查找方法
2016/03/01 Javascript
jQuery深拷贝Json对象简单示例
2016/07/06 Javascript
js中string和number类型互转换技巧(分享)
2016/11/28 Javascript
实现div内部滚动条滚动到底部和顶部的代码
2017/11/15 Javascript
初学node.js中实现删除用户路由
2019/05/27 Javascript
npm全局环境变量配置详解
2020/12/15 Javascript
[04:19]DOTA2完美大师赛第四天精彩集锦
2017/11/26 DOTA
Python 变量类型及命名规则介绍
2013/06/08 Python
pandas Dataframe行列读取的实例
2018/06/08 Python
python 把列表转化为字符串的方法
2018/10/23 Python
Python网页正文转换语音文件的操作方法
2018/12/09 Python
Python交互式图形编程的实现
2019/07/25 Python
面向对象学习之pygame坦克大战
2019/09/11 Python
pytorch dataloader 取batch_size时候出现bug的解决方式
2020/02/20 Python
python3 xpath和requests应用详解
2020/03/06 Python
python批量合成bilibili的m4s缓存文件为MP4格式 ver2.5
2020/12/01 Python
纽约手袋品牌:KARA
2018/03/18 全球购物
英国HYPE双肩包官网:英国本土时尚潮牌
2018/09/26 全球购物
幼儿园教师节活动方案
2014/02/02 职场文书
二手房购房协议书范本
2014/10/05 职场文书
失职检讨书大全
2015/01/26 职场文书
幼儿教师个人总结
2015/02/05 职场文书
全国爱牙日活动总结
2015/02/05 职场文书
大学生自我评价范文
2015/03/03 职场文书
堂吉诃德读书笔记
2015/06/30 职场文书
感恩教育主题班会
2015/08/12 职场文书
《狼牙山五壮士》读后感:宁死不屈,视死如归
2019/08/16 职场文书
如何优化vue打包文件过大
2022/04/13 Vue.js