权限路由和导航

80 阅读2分钟

权限路由和导航

项目vue2/vue-router

流程

  1. 使用VueRouter插件
  2. new 一个挂载白名单的实例 router
  3. 进入路由守卫 router.beforeEach
  4. 根据store.state的登录状态判断是否已配置过路由
  5. 若无,发起请求,再把相应的数据转为树形,将数据和登录状态存储在store中
  6. 树形结构化的数据 -> vue 路由结构
  7. router.addRoutes 动态添加路由
  8. next跳转
  9. 将router实例挂载在vue配置上
  10. 菜单组件通过监听store里的路由数据动态加载导航

数据流程

  1. uerId -> 后端 API(路由权限API)
  2. 后端 -> 用户对应路由权限列表 -> 前端(JSON)
  3. JSON-> 树形结构化
  4. 树形结构化的数据 -> vue 路由结构
  5. 路由结构动态 -> 静态路由
  6. 树形结构化的数据 -> 菜单组件
// 后端返回的用户数据格式
[
  {
    id, 
    name, 
    auth: [2,3,4], // 有权限的路由 id 
  }
]
// 用用户id去请求,后端返回的需要加载的路由
[
  {
    id, 
    pid, //parentId 
    path, 
    name, 
    link, 
    title
  }, 
  {...}
] 
  1. router.js
import Vue from 'vue'
import VueRouter from 'vue-router'
import { generateRouter } from '@/libs/utils'
import store from '@/store'const Home = () => import('../views/Home.vue') 
const NotFound = () => import('../views/NotFound.vue') 
​
// 0.使用VueRouter插件
Vue.use(VueRouter)
​
const routes = [
  {
    path: '/',
    name: 'home',
    component: Home
  }, {
    path: '*',
    name: 'NotFound',
    component: NotFound
  }
  
]
​
// 1. new 一个挂载白名单的实例 router
const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  routes
})
​
// 2.进入路由守卫 router.beforeEach
router.beforeEach(async(to, from, next) => {
  // 3.根据store.state的登录状态判断是否已配置过路由
  if(!store.state.hasAuth) {
    // 4.若无,发起请求,再把相应的数据转为树形,将数据和登录状态存储在store中
    await store.dispatch('fetchUserRouters')
    // 5.树形结构化的数据 -> vue 路由结构
    const newRoutes = generateRouter(store.state.userRouters)
    console.log('1',router)
    // 6.router.addRoutes添加路由
    router.addRoutes(newRoutes)
    console.log('2',router)
    // 7.next跳转
    next({path: to.path})
  } else {
    next();
  }
})
export default router

main.js

// 8.将router实例挂载在vue配置上
new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
​
// 9.监听store里的路由数据动态加载导航

util.js

// 先按 id 排序,从小到大
// let routersSort = data.sort((after, cur) => {
//   return after.id - cur.id  // 按大于的结果
// })// 总的递归思路
// 分为父级和子级,c.pid === p.id 时,把子级放入父级的 children 对象中
// 拷贝 children 删除 c,[c] 作为父级,_c 为 子级,进行递归// 1. 把第一级的父级和子级分离出来
// 2. 放入递归 dataToTree(parents, children)
// 3. parents 遍历里 children 遍历里
// 4. 判断 c.pid === p.id,c 是 p 的子级
// 5. 把子级 c 放入父级 p 的 children 对象中
// 5. 先深拷贝一份子级 _c,删除 _c 里的 c 项
// 6. c 为对象,放进数组,[c] 作为父级,_c 为 子级,进行递归,dataToTree([c], _c) // json->tree
export function formatRouterTree (data) {
​
  // 把父级和子级分离出来
  let parents = data.filter(p => p.pid === 0),  // 第一级的父级
  children = data.filter(c => c.pid !== 0)  // 第一级的子级
​
  dataToTree(parents, children)
​
  function dataToTree(parents, children) {
​
    parents.map((p) => {
      children.map((c, c_i) => {
        // c 是 p 的子级
        if(c.pid === p.id) {
          // 1. 把子级放入父级的 children 对象中
          if(p.children) {
            // 之前已有子级
            p.children.push(c)
          } else {
            // 之前无子级,这是第一个
            p.children = [c]
          }
​
          // 1. 进行递归
          // 深拷贝复制一份
          let _c = JSON.parse(JSON.stringify(children))
          // 删除已找到父级的 c
          _c.splice(c_i,1)
          // c 作为父级,_c 作为子级
          dataToTree([c], _c)
        }
      })
    })
  }
  return parents
}
​
// tree -> routers
export function generateRouter (userRouters) {
  let newRouters = userRouters.map(r => {
    let route = {
      path: r.path,
      name: r.name,
      component: () => import(`@/views/${r.componentPath}`)
    }
​
    if(r.children) {
      route.children = generateRouter(r.children)
    }
​
    return route
  })
​
  console.log('util-newRouters',newRouters)
  return newRouters
}