其他router相关内容索引

序号

内容

1

vue router 整合引入

2

vue router 模块化开发

3

vue router 动态路由及菜单实现之一

4

vue router 动态路由及菜单实现之二

5

vue router 动态路由及菜单实现问题汇总

6

vue el-menu多级菜单递归

7

vue router 懒加载常见写法

之前将路由引入,按模块简单划分后,准备将路由和菜单结合起来。发现需要前端维护一遍菜单,后端也要维护一遍菜单,这就有点蛋疼。每次后端改了一点,前端也要相应的改一波配置。
看了一波其他大神的,也是用两种方式实现的,但具体的细节方面很少有提到,router这种东西看不到具体的路径就会很懵逼。

vue router 动态路由实现之一

router.addRoutes

要动态添加路由,主要用到的方法就是router.addRoutes

但这个方法在官方api的解释:

element ui 动态路由 菜单 vue router动态菜单_addRoutes


没错,就是这么简单,这个看第一眼就知道要苦了。但该用还得用嘛,要踩的坑肯定要踩的。用法看起来很简单,就只要符合RouterConfig的格式数组就可以了。

element ui 动态路由 菜单 vue router动态菜单_addRoutes_02


就是像这样的数组,直接传进去就可以了。手写代码有点不好的就是容易错了找不到,所以如果不是为了学习,还是复制粘贴的效率高些。

router.js的改造

router.js路由文件的改造思路:
1、加载静态路由,用户能直接访问的路由,不需要判断权限就需要直接展示的。
2、加载动态路由,需要判断用户权限,需要从后台传过来,需要动态生成菜单的。

router.js

const router = new VueRouter({
  mode: 'history',
  base: process.env.BASE_URL,
  scrollBehavior: () => ({ y: 0 }),
  routes: []
})

/* 加载可以直接访问的路由 */
router.addRoutes(constantRoutes1);
/* 加载后端路由 */
router.addRoutes(filterAsyncRouter(asyncRoutes));
/* 加载 404 */
router.addRoutes(constantRoutes2);

// 路由变化时
router.beforeEach((to, from, next) => {
  if (document.title !== to.meta.title) {
    document.title = to.meta.title;
  }
  next()
})

export default router

新建 constrouter.js

/* constantRoutes静态路由,所有用户均可访问 */
export const constantRoutes1 = [
    {
        path: '/',
        redirect: '/login'
    },
    // 系统登录    
    {
        path: '/login',
        name: 'Login',
        component: () => import('@/layout/login'),
        meta: {
            title: '用户登录'
        }
    },
}

/* constantRoutes静态路由,所有用户均可访问 */
export const constantRoutes2 = [
    {
        path: "/system",
        redirect: '/system',
    },
    ...ERROR,
    {
        path: '/*',
        redirect: '/404',
    },
]

动态生成路由

动态生成路由最关键的是怎么将 component 后面的参数由后台传递过来,并进行转化成router可以识别的样子,毕竟后台不可能传这样的过来,这个也不是一个字符串。

() => import('@/layout/login'),

这里先看一眼之前的菜单文件,这里已经把component参数给加好了,如果直接用el-menu的话,这个参数用不上。role也是新加的,后续留着判断菜单权限用。

const asyncRoutes = [
    {
        "path": "/system",
        "name": 'SystemIndex',
        "component": "system",
        "meta": {
            "title": "系统管理",
            "icon": "el-icon-setting",
            "role": [
                "admin"
            ]
        },
        "children": [
            {
                "path": "role",
                "component": "system/role",
                "meta": {
                    "title": "角色管理",
                    "icon": "el-icon-star-on",
                    "role": [
                        "admin"
                    ]
                }
            },
            {
                "path": "user",
                "component": "system/user",
                "meta": {
                    "title": "用户管理",
                    "icon": "el-icon-user-solid",
                    "role": [
                        "admin"
                    ]
                }
            },
            {
                "path": "menu",
                "component": "system/menu",
                "meta": {
                    "title": "菜单管理",
                    "icon": "el-icon-menu",
                    "role": [
                        "admin"
                    ]
                }
            },
            {
                "path": "trans",
                "component": "system/trans",
                "meta": {
                    "title": "多系统",
                    "icon": "el-icon-s-opportunity",
                    "role": [
                        "admin"
                    ]
                }
            },
            {
                "path": "test",
                "component": "system/home",
                "meta": {
                    "title": "系统测试",
                    "icon": "el-icon-success",
                    "role": [
                        "admin"
                    ]
                }
            }
        ]
    },
]}

注意:这里的component千万别手贱写个components。多个s,component匹配不上,还找不到为什么真的会怀疑人生。

现在需要将这里的component的字符串参数转化一下

//遍历后台传来的路由字符串,转换为组件对象
export function filterAsyncRouter(asyncRouterMap) { 
    const accessedRouters = asyncRouterMap.filter(route => {
        if (route.component) {
            if (route.component === 'system') {
                route.component = system
            } else {
                // console.log("load:" + loadView(route.component));
                route.component = loadView(route.component)
                // console.log("import:" + __import(route.component));
                // route.component = __import(route.component)
            }
        }
        if (route.children && route.children.length) {
            route.children = filterAsyncRouter(route.children)
        }
        return true
    })
    return accessedRouters
}

/* 加载路由组件,两种方式均可 */
const loadView = (view) => { // 路由懒加载
    // return (resolve) => require([`@/views/${view}`], resolve)
    return () => import('@/views/' + view)
}

这里要规划好应用页面的路径,不然就得多加判断了。

查看动态路由

这块可以说是最关键了,不然这个生成完了那里写错了,为什么找不到路径,总是404就会很难受。

在官网上找到了这个方法

$route.matched

类型: Array<RouteRecord>
一个数组,包含当前路由的所有嵌套路径片段的路由记录 。路由记录就是 routes 配置数组中的对象副本 (还有在 children 数组)。

当 URL 为 /foo/bar,$route.matched 将会是一个包含从上到下的所有对象 (副本)。

找了半天的路径在router.matcher中发现了。静态和动态路由都使用addrouters方法添加,所有的path就会addRouters中的Scopes中转成一个pathList。

element ui 动态路由 菜单 vue router动态菜单_vue_03


整个router关键信息的位置,这里面还有其他的一些 alias、match、nameMap,还有对应的redirect。所以在后续后台传过来的东西中

这些也是可以包含使用了。

element ui 动态路由 菜单 vue router动态菜单_addRoutes_04

el-menu动态生成菜单

动态路由完成了,前端基本上没什么需要改的,el-menu 加上router属性,index属性将会用于激活route action的path

官方原文

whether vue-router mode is activated. If true, index will be used as 'path' to activate the route action

element ui 动态路由 菜单 vue router动态菜单_addRoutes_05


这里就没有写递归了,直接 for和if写了三层判断,一般菜单也不会超过三层。

最终效果如下

element ui 动态路由 菜单 vue router动态菜单_vue router_06