element-admin-template模板项目动态添加路由

最近项目要求鲁有需要动态获取,从后端返回数据进行处理。我的项目模板是基于element-damin-template的。官方文档也有介绍

https://panjiachen.github.io/vue-element-admin-site/zh/guide/essentials/permission.html#%E9%80%BB%E8%BE%91%E4%BF%AE%E6%94%B9

通常的路由使我们自己在router/index里面自己定义的路由,写死的一些路由,这些路由在加载时如果不做处理就会直接全部加载,而后台数据一般我们需要做权限控制。一般来说都是需要后台返回我们这个账号所能展示的路由,由我们动态加载。

首先,我们需要后端接口,携带这些权限路由信息。
其次,我们要想办法加载到我们的router中。

  1. 在我们的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
  1. 定义好了公共路由,下一步就是拿到后端返回的路由表,进入store的permission.js文件
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中实现动态权限控制

中间遇到过多次很有趣的问题,当时忘记记录,如有问题,欢迎讨论。

好记性不如烂笔头,早起的鸟儿有虫吃,冲鸭!!!

你可能感兴趣的:(vue,后台管理权限,vue)