当前位置:   article > 正文

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

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
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80

这个里面,我们后端返回的数据需要进行两次处理,大家根据后端数据格式酌情处理就可以。
3. 之后我们在getters.js里面设置

 permission_routes: state => state.permission.routers
  • 1

并且在layout的sidebar/index.vue的computed引入,我的项目导航栏不太一样就不多展示了

...mapGetters(["permission_routes","sidebar"]),
  • 1

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
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

这样一套流程下来基本上就完事了。

总结: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;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29

这个就是对路由的一个解析重组,由于后端返回数据是数组对象单层的,非树形结构模式,需要转化为符合路由规则的我们定义好的嵌套结构,这里做了更改。一般情况,后端返回的动态路由结构是
[{‘a’:'b},{‘a’:'b}]
类似这种的单层表结构应该都是可以用的

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/凡人多烦事01/article/detail/611006
推荐阅读