# 路由和菜单

在el-admin-layout中,路由和菜单是分离的,也就是说,你在定义完路由后,还需要定义一份菜单并传递给el-admin-layout:

import {appMutations} from 'el-admin-layout'

//定义路由
const routes = [{
    path: '/',
    component: Layout,
    children: [
        {
            path: 'index',
            component: Index,
            meta: {title: '首页'}
        }
    ]
}]

const menus = [{
    fullPath: '/',
    meta: {title: '根菜单'},
    children: [{
        fullPath: '/index',
        meta: {title: '首页'}
    }]
}]

//传递给el-admin-layout
//这一步可以在放在适当的时机执行,比如像服务器请求数据成功后
appMutations.menus(menus)

可以看到路由和菜单的配置是比较相似的,这样能够方便地将路由转换成菜单

注意

el-admin-layout接收到的菜单会全部显示,如果想要某个菜单不显示(常见的权限控制),请传递过滤后的菜单

强烈要求

如果在传递了菜单之后,想对菜单数组做增减,请调用appMutations.menus(在菜单数据量较大时,可能会有性能问题)

如果想修改菜单的meta,可以通过调用appMutations.modifyMenuMeta来实现

尽量不要通过appGetters.menus来修改,尽管这样可行,官方文档 (opens new window)

# 路由标识

每个路由都需要有一个独一无二的标识,这个标识会用在缓存、刷新、跳转、避免路由组件复用等方面

路由标识的获取:

  1. 如果路由meta中的usePathKeytrue,则使用route.path作为路由唯一标识

  2. 如果路由meta中的useFullPathKeytrue,则使用route.fullPath作为路由唯一标识

  3. 如果路由中的name有值,则使用route.name作为路由唯一标识,否则使用route.fullPath

源码
function getRouterKey(route) {
    const {name, path, fullPath, meta: {usePathKey, useFullPathKey} = {}} = route
    return usePathKey
        ? path
        : useFullPathKey
            ? fullPath
            : name || fullPath
}

# 页签

页签栏上的页签数组存放于tagsViewStore.visitedViews

基本上,页签对象的数据结构可以认为是meta.title恒不为空的路由对象(vue-router.Route)

想要在页签栏上显示,那么路由meta必须要有标题(title非空或dynamicTitle返回值非空)

页签分为固定显示的页签和路由生成的页签两种:

# 固定显示的页签

在页签栏初始化后,遍历传入el-admin-layout的菜单数组,菜单metaaffixtrue时, 调用vue-router.resolved获取菜单对应的路由对象,若路由对象拥有非空title,则加入页签数组。 固定显示的页签没有关闭按钮,但可以通过tagsViewMutations来强行控制

注意

如果菜单需要固定显示,那么对应的路由对象不要使用meta.dynamicTitle这类需要传入当前路由的函数型属性, 因为生成固定页签的时机是在页签栏初始化后,那么传入的路由可能不是期望的当前路由

# 路由生成的页签

当路由发生变化时,如果目标路由meta中的dynamicTitle为函数类型且返回了非空的值或者title非空,那么将目标路由加入页签数组

# 和缓存的关系

是否在页签栏上显示和是否能够缓存没有必然关系!

一个路由虽然不会显示在页签中,但它仍有机会被缓存(虽然基本没有应用场景)

# 缓存

el-admin-layout默认开启了缓存功能,如果发现缓存不了,请先确认是否启用了页签栏并且开启了页签栏的缓存功能:

//两者必须同时为true
tagsViewGetters.enabled === true && tagsViewGetters.enableCache === true

此外,el-admin-layout不支持深度大于2的嵌套路由的缓存,如果有这种路由,请将其转换为深度为2的路由!

转换前:

const routes = {
    path: '/',
    component: Layout,
    children: [
        {
            path: 'nested',
            component: Nested,
            children: [
                {
                    path: 'child',
                    component: Child
                }
            ]
        }
    ]
}

转换后:

//如果Nested组件使用了公用的组件,那么Child可以用动态组件<component/>重构

const routes = {
    path: '/',
    component: Layout,
    children: [
        {
            path: 'nested/child',
            component: Child
        }
    ]
}

# 缓存规则

在开启了缓存功能的前提下,一个路由页面想要被缓存需要满足一些条件:

  1. 如果路由meta中的noCache不为true,那么继续下面的判断,否则不缓存

  2. 如果路由的唯一标识不是name,缓存

  3. 路由的唯一标识是name,并且和页面组件的name相同时才缓存,否则不缓存:

const routes = [{
    path: '/',
    component: Layout,
    children: [
        {
            path: 'index',
            name: 'index', // 这里的name需要和IndexPage的name相同
            component: IndexPage,
        }
    ]
}]

更详细的信息可以查看tagsViewMutations.addCacheOnly方法和<KeepViewAlive/>组件源码

# 内嵌iframe

只要路由meta中的iframe有值,就视为iframe,跳转到该路由时将打开一个src为iframe的iframe

如果两个不同路由使用了相同的iframe值,那么他们会打开同一个iframe,除此之外iframe的缓存条件和其他页面没有区别

小优化

如果路由meta设置了iframe,那么component可以不用设置,避免不必要的页面渲染

# 外链

当菜单中的fullPath'http'开头时,则视为外链,其被点击时将使用window.open(fullPath)来打开一个新窗口

注意

如果外链菜单是根节点并且有子级菜单:

const externalMenu = {
    fullPath: 'https://www.baidu.com',
    children: [...]
}

那么在导航模式为'mix'时,点击该菜单会直接打开新页面,而不会切换子级菜单

所以最好将外链设为叶子菜单

# 高亮菜单

导航菜单(侧边栏或顶部菜单)是根据菜单的fullPath是否为route.pathroute.meta.activeMenu其一来控制当前高亮的菜单的

比如有如下菜单:

const menu = {fullPath: '/test'}

当路由为'/test''/test?x=1'时,这个菜单都会被高亮

一些情况下,路由没有对应的菜单(比如详情页),需要通过菜单meta的activeMenu自行指定一个高亮的叶子菜单:

const route = {
    path: '/dynamic/:id',
    component: Dynamic,
    meta: {
        activeMenu: '/list',
        dynamicTitle: route => `动态页${route.params.id}`
    }
}

const menu = {
    fullPath: '/list',
    meta: {
        title: '列表'
    }
}

WARNING

除非是外链,否则不要在fullPath中使用url参数,比如:

const menu = {fullPath: '/test?x=1'}

不管路由是'/test'还是'/test?x=1',这个菜单都不会被高亮

除非设置了菜单meta的activeMenu(但是默认的面包屑会出问题):

const menu = {fullPath: '/test?x=1', activeMenu: '/test?x=1'}

# 避免组件复用

如果有不同路由使用了相同的组件,请确保这些路由的唯一标识不同,否则会出现组件复用的情况:

const routes = [
    {
        path: '/index',
        name: 'index',
        component: ReusablePage
    },
    {
        path: '/index2',
        name: 'index2',
        component: ReusablePage
    },
    {
        path: '/detail/:id',
        component: ReusablePage,
        meta: {
            usePathKey: true
        }
    }
]
上次更新:: 10/16/2021, 1:03:10 PM