赞
踩
最近项目要求鲁有需要动态获取,从后端返回数据进行处理。我的项目模板是基于element-damin-template的。官方文档也有介绍
通常的路由使我们自己在router/index里面自己定义的路由,写死的一些路由,这些路由在加载时如果不做处理就会直接全部加载,而后台数据一般我们需要做权限控制。一般来说都是需要后台返回我们这个账号所能展示的路由,由我们动态加载。
首先,我们需要后端接口,携带这些权限路由信息。
其次,我们要想办法加载到我们的router中。
import Layout from '@/layout/index' import Vue from 'vue' import Router from 'vue-router' Vue.use(Router) export const constantRoutes = [ // 登录页 { path: '/login', component: (resolve) => require(['@/views/login/index'], resolve), hidden: true }, // 首页 { path: '/', component: Layout, redirect: '/dashboard', children: [{ path: 'dashboard', name: 'Dashboard', component: (resolve) => require(['@/views/dashboard/index'], resolve), meta: { title: '首页', affix: true } }] }, //报错页面 { path: '/404', component: (resolve) => require(['@/views/404'], resolve), hidden: true }, ] const createRouter = () => new Router({ mode: 'history', scrollBehavior: () => ({ y: 0 }), routes: constantRoutes }) const router = createRouter() export function resetRouter() { const newRouter = createRouter() router.matcher = newRouter.matcher } router.$addRoutes = function(params) { router.matcher = new Router({ mode: 'history' }).matcher; router.addRoutes(params) } export default router
import { getMenus } from '@/api/setUp/menu'; import Layout from '@/layout/index'; import vue from '@/main'; import { constantRoutes } from '@/router'; const permission = { state: { routers: [], addRouters: [] }, mutations: { SET_ROUTES: (state, router) => { state.addRouters = router; state.routers = constantRoutes.concat(router); } }, actions: { // 生成路由 GenerateRoutes({ commit }) { return new Promise(resolve => { // isLogin: 0 返回所有菜单 isLogin: 1 根据角色返回对应的菜单 let data = { isLogin: 1 } // 获取后端返回的路由表 getMenus(data).then(res => { // 处理后端返回的路由表转化为嵌套模式 for (var i = 0; i < res.data.length; i++) { res.data[i].children = [] } let routes = vue.handleTree(res.data, "id"); // 调用 getAsyncRoutes转化为我们需要的正确路由格式 let accessedRoutes = getAsyncRoutes(routes) //添加404 accessedRoutes.push({ path: '*', redirect: '/404', hidden: true }) // 设置综合路由表 commit('SET_ROUTES', accessedRoutes) // 导出综合路由表 resolve(permission.state.routers) }) }) } } } /** 1. 把后台返回菜单组装成routes要求的格式 2. @param {*} routes */ export function getAsyncRoutes(routes) { const res = [] routes.forEach(item => { const newItem = {} if (item.component) { if (item.component === 'layout') { newItem.component = Layout } else { newItem.component = loadView(item.component) //这种格式的路由加载方式会出现问题,具体原因可以了解下webpack,我们使用require方式就OK了 // newItem.component = () => // import (`@/views/${item.component}`) } } newItem.meta = { title: item.name } newItem.name = item.path newItem.path = `/${item.path}` if (item.children && item.children.length) { newItem.children = getAsyncRoutes(item.children) } res.push(newItem) }) return res } export const loadView = (view) => { // 路由懒加载 return (resolve) => require([`@/views/${view}`], resolve) } export default permission
这个里面,我们后端返回的数据需要进行两次处理,大家根据后端数据格式酌情处理就可以。
3. 之后我们在getters.js里面设置
permission_routes: state => state.permission.routers
并且在layout的sidebar/index.vue的computed引入,我的项目导航栏不太一样就不多展示了
...mapGetters(["permission_routes","sidebar"]),
4.进入permission.js文件,这个文件是我们的路由拦截配置文件。在这里面调用我们store里设置的GenerateRoutes,然后添加router中
import { getToken } from '@/utils/auth' // get token from cookie import getPageTitle from '@/utils/get-page-title' import { Message } from 'element-ui' import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style import routers from './router' import store from './store' NProgress.configure({ showSpinner: false }) // NProgress Configuration const whiteList = ['/login'] // 白名单 routers.beforeEach(async(to, from, next) => { // 进度条开始 NProgress.start() // 页面标题 document.title = getPageTitle(to.meta.title) // 确定用户是否已登录 const hasToken = getToken() if (hasToken) { if (to.path === '/login') { next({ path: '/' }) NProgress.done() } else { const hasGetUserInfo = store.getters.name if (hasGetUserInfo) { next() } else { // 重点就是在这里面进行配置!!!! try { // 确认用户登录 await store.dispatch('user/getInfo') // 调用store方法获取路由信息并添加到路由表中 const accessRoutes = await store.dispatch('GenerateRoutes') // 通过手动的$addRoutes方法删除旧的路由表并且添加 routers.$addRoutes(accessRoutes) routers.options.routes = accessRoutes next({...to, replace: true }) } catch (error) { // 删除令牌并转到登录页面重新登录 await store.dispatch('user/resetToken') Message.error('Has Error') next(`/login?redirect=${to.path}`) NProgress.done() } } } } else { /* has no token*/ if (whiteList.indexOf(to.path) !== -1) { // 在免费登录白名单中,直接进入 next() } else { //其他没有访问权限的页面将被重定向到登录页面. next(`/login?redirect=${to.path}`) NProgress.done() } } }) routers.afterEach(() => { // finish progress bar NProgress.done() })
这样一套流程下来基本上就完事了。
总结:1.定义公共路由;
2.store中设置获取路由的方法(获取并处理后端返回的路由表数据为我们需要的路由格式)
3.在路由拦截中调用store的方法获取路由数据并添加到router中实现动态权限控制
中间遇到过多次很有趣的问题,当时忘记记录,如有问题,欢迎讨论。
好记性不如烂笔头,早起的鸟儿有虫吃,冲鸭!!!
看到有朋友评论找不到handleTree方法,这是我的疏忽,这个方法是我定义在utils里面的一个方法,挂载在了vue上,我来贴出来
/** * 构造树型结构数据 * @param {*} data 数据源 * @param {*} id id字段 默认 'id' 'id' * @param {*} parentId 父节点字段 默认 'parentId' * @param {*} children 孩子节点字段 默认 'children' * @param {*} rootId 根Id 默认 0 */ export function handleTree(data, id, parentId, children, rootId) { id = id || 'id' parentId = parentId || 'parentId' children = children || 'children' rootId = rootId || Math.min.apply(Math, data.map(item => { return item[parentId] })) || 0 //对源数据深度克隆 const cloneData = JSON.parse(JSON.stringify(data)) //循环所有项 const treeData = cloneData.filter(father => { let branchArr = cloneData.filter(child => { //返回每一项的子级数组 return father[id] === child[parentId] }); branchArr.length > 0 ? father.children = branchArr : ''; //返回第一层 return father[parentId] === rootId; }); return treeData != '' ? treeData : data; }
这个就是对路由的一个解析重组,由于后端返回数据是数组对象单层的,非树形结构模式,需要转化为符合路由规则的我们定义好的嵌套结构,这里做了更改。一般情况,后端返回的动态路由结构是
[{‘a’:'b},{‘a’:'b}]
类似这种的单层表结构应该都是可以用的
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。