权限路由和导航
项目vue2/vue-router
流程
- 使用VueRouter插件
- new 一个挂载白名单的实例 router
- 进入路由守卫 router.beforeEach
- 根据store.state的登录状态判断是否已配置过路由
- 若无,发起请求,再把相应的数据转为树形,将数据和登录状态存储在store中
- 树形结构化的数据 -> vue 路由结构
- router.addRoutes 动态添加路由
- next跳转
- 将router实例挂载在vue配置上
- 菜单组件通过监听store里的路由数据动态加载导航
数据流程
- uerId -> 后端 API(路由权限API)
- 后端 -> 用户对应路由权限列表 -> 前端(JSON)
- JSON-> 树形结构化
- 树形结构化的数据 -> vue 路由结构
- 路由结构动态 -> 静态路由
- 树形结构化的数据 -> 菜单组件
// 后端返回的用户数据格式
[
{
id,
name,
auth: [2,3,4], // 有权限的路由 id
}
]
// 用用户id去请求,后端返回的需要加载的路由
[
{
id,
pid, //parentId
path,
name,
link,
title
},
{...}
]
- 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
}