vue动态加载路由_实现vue动态加载路由器设置

时间: 2018-11-10阅读: 4474标签: 路由

我们的通用的后台管理系统中,我们会根据权限的粗细不同,会对每个角色每个权限每个资源进行控制。同样的我们也需要实现一个这样的功能。 这篇文章我将主要讲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页面的。

 

作者: yukong
链接:https://cloud.tencent.com/developer/article/1181044


站长推荐

1.云服务推荐: 国内主流云服务商,各类云产品的最新活动,优惠券领取。地址:阿里云腾讯云华为云

链接: http://www.fly63.com/article/detial/1321

Flutter页面切换(命名路由)

使用基本路由相对简单灵活,适用于应用中页面不多的场景。而在应用中页面比较多的情况下,再使用基本路由,会导致大量的重复代码,此时使用命名路由会非常方便

实现一个前端路由,如何实现浏览器的前进与后退?

如果要你实现一个前端路由,应该如何实现浏览器的前进与后退 ?首先浏览器中主要有这几个限制,让前端不能随意的操作浏览器的浏览纪录:没有提供监听前进后退的事件。

Flutter开发之导航与路由管理

所谓路由管理,就是管理页面之间如何跳转,也被称为导航管理。这和原生开发类似,无论是Android还是iOS,导航管理都是通过维护一个路由栈来实现的,路由入栈(push)操作对应打开一个新页面,路由出栈(pop)操作对应页面关闭操作

如何制作自己的原生 JavaScript 路由

当你想到路由时,通常会想到类似 React 之类的库。但实际上,这些库和框架仍然使用 vanilla JavaScript。那么该怎么实现呢?我遇到了很多出于各种原因想要自己创建路由的人。

React Router拦截器(钩子)、静态路由、route-view 实现

React Router 再 v3 版本之前 是有 onEnter 钩子函数的,也支持静态路由配置;,但到了 v4 版本后钩子函数被移除,官方说是为了将此提供给开发者,由开发者自由发挥。既然如此我们就只能自己实现

vue-router的简易实现

现在很多项目的前端都是用vue单页面实现的,而单页面中最重要的一个环节就是路由,今天来实现一个简易版本的vue-router。

前端 Vue路由返回恢复页面状态

在使用 Vue 开发前端的时候遇到一个场景:在首页进行一些数据搜索,点击搜索结果进入详情页面,浏览详情页后返回主页。但这时候之前的搜索记录和翻页就消失了,用户体验不好。所以需要在返回后恢复跳转前的页面参数状态

Vue 嵌套路由、路由守卫

嵌套路由挺常用的,比如导航栏有首页、文章、想法、留言4个模块,我们以嵌套路由的形式集成这些模块,在导航栏中点击对应的条目,就会路由到对应的页面(下方显示对应的页面),和html的<iframe>效果差不多。

使用 webpack 插件自动生成 vue 路由文件

一款自动生成 vue 路由文件的 webpack 插件 vue-route-webpack-plugin 在项目中试点成功了,现在在项目中已经不需要再维护路由配置文件了,由插件自动生成,节省了大家维护路由的时间。

Flutter路由导航

我们通常会用屏(Screen)来称呼一个页面(Page),一个完整的App应该是有多个Page组成的。通过点击BottomNavigationBarItem来设置IndexedStack的index属性来切换,除了上面这种管理页面的方式,我们还需要实现其它功能的页面跳转

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!