Talk is cheap

Vue后端动态路由实现

Vue后端动态路由

Vue路由的两种实现方式

在vue的项目中,关于路由这一块的实现,大概有两种的方法:前端路由,后端路由。各有特点,可以根据自身项目情况酌情选取

  • 前端路由: 所有的vue路由都在前台维护,每个路由的meta元信息里带有一个访问该路由所需的权限字符串。用户登陆系统后,前台请求获取用户的角色,然后用这个角色来过滤前端路由。

  • 后端路由: 用户登陆后,后台会给前台一个token,这个token里包含了用户的角色等基本信息,用户向后台请求获取路由信息, 此时前台获取到的路由信息,就是已经过滤后的路由。 也就是说后台返回的路由,就是用户能够访问的路由,前台不用其他处理。相对来说,需要处理的问题更少只需要加载路由即可。个人更倾向于后端路由的实现。

动态路由的实现

网上关于vue动态路由的实现方法,大多都是只写了一个大致的思路,或者只是些代码片段,又或者对于其中实现的关键点没有介绍到位,项目下载下来发现运行不了,无法嵌入运用到自身项目中。基于此,本文提供了详细了源码,以及其中关键的技术点。

  1. 开发环境: "vue": "2.6.10" ,"vue-router": "3.0.6", "vuex": "3.1.0" ,"axios": "0.18.0", 基于Vue-Element-Template基础模板来实现, 当然其他的框架也都实用, 只是项目的文件目录可能有些区别。

  2. 源码地址 :https://gitee.com/giker/vue-admin-template-tabnav.git

  3. 既然是后端动态路由,那么这个动态的路由表就应该从动态获取,为了方便,这里使用的mock数据,下面是我的mock数据,当然你也可以直接使用后台数据。只要能够返回router格式的 json数据就行了

    const data = Mock.mock({      
      'menus':[       
        {
          path: '/product',
          component: 'layout',   
          children: [
            {
              path: 'index',
              name: 'Product',
              component: 'views/product/index',
              meta:{title: 'Product',icon: 'form'}
            }
          ]
        }
      ]
    })
  4. 有了后台数据,那么就可以开始进入正题了。 打开项目src/permission 文件,注意到里面的router.beforeEach方法,这个里面写的是路由守卫,来判断用户是否登陆,如果没有登陆就跳转到登陆页面,如果登陆的话就获取用户信息,这段代码相信都能够无压力看懂。 await store.dispatch('user/getInfo') 这里调用了一个Vux中的action,用异步方法来获取用信息。 现在我们就在这句话下加入我们的代码

    await store.dispatch('menu/getSideMenus'); //调用action的方法来异步加载后台路由

  5. 当然上面的action 目前是不存在的,我们要写这么一个action 方法,在 src/store/modules 下新建一个文件,来写我们的action方法,如下:

    import { getList } from '@/api/menu'
    import router from '@/router'
    import { traverseRoutes } from '@/utils/route'
    
    const actions = {
    
      getSideMenus({ commit, state }) {
        return new Promise((resolve, reject) => {
          getList().then(response => {
            const menus = response.data.menus
            let routes = traverseRoutes(menus);
            router.addRoutes(routes)
            router.options.routes = router.options.routes.concat(routes);
            resolve()
          }).catch(error => {
            reject(error)
          })
        })
      }
    }
    
    export default {
      namespaced: true,
      actions
    }
  6. 这里面的getList方法,是用户获取后台的路由信息的,返回的是json字符串。 现在最重要的点就是要把这里json字符串转换成路由对象了,重中之重是:如何把 componet 属性的字符串转换为 需要引入的组件。 这一过程被写在了 traverseRoutes 这个函数中:

    export function traverseRoutes(menus){
      let routes = menus.map( menu =>{
        if(menu.component){
          let name = menu.component;
          menu.component = ()=> import(@/${name})
        }
    
        if(menu.children && menu.children.length){
          menu.children = traverseRoutes(menu.children);
        }
        return menu;
      })
      return routes;
    }

    现在所有的核心代码都列出来了,来看看这其中的“坑”吧。

    • 首先是import() 动态引入文件。import() 的参数不能是变量! 这里采用了js字符串模板的方法来规避这个问题。

    • 这还不算完, 注意import中的参数: 使用了 @/ 开头, 这样,webpack会把这个目录下的所有js都给编译了,然后再按照名字来加载,以实现懒加载! 这里不能够吧直接把 @/写到name 变量里,否则的话 webpack 就不能知道预编译哪个文件夹下的文件了。

    尤其注意上面的写法,用了一个 let name = menu.component 而没有直接写成 import(@/${menu.component})

    • 把后台的json数据转换成router对象以后,还差最后一步,要把我们转换后的 router 添加到系统路由里!注意getSideMenus这个函数中的两句很重要的代码 :

      router.addRoutes(routes)
      router.options.routes = router.options.routes.concat(routes);

      注意这两句 router.addRoutes() 是把我们生成路由添加到系统路由里,有了这句,你在地址栏直接输入地址,我们的页面就能够展现出来了。 那么第二句是干什么的呢?
      这里又是一个坑:router.options.routes 是获取系统路由里的所有路由,但是使用了addRoutes()之后,router.options.routes并不会自动把我们添加的路由加入进来,需要我们手动维护!
      关于这一点的解释,vue-router的作者有过解释,https://github.com/vuejs/vue-router/issues/1859

    所有的东西都在这里了,剩下的就要你自己去梳理一下了。

未经允许不得转载:CheapTalk » Vue后端动态路由实现
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!