我们在搭建Web的后台管理系统时,会选择 ElementUI 进行快速搭建,但是在某些场景下,单纯的使用组件是不能满足要求的。
因为需求是在不断增加,不断变化的,如果像 ElementUI 给的示例去维护后台管理系统的菜单栏的话,代码会非常臃肿,维护起来也不是很方便:
菜单是一个树形结构,VueRouter的配置项 routes 也是树形结构,每一个具体的路由都对应着一个页面,因此可以利用 routes 来配合 ElementUI菜单组件 动态生成菜单。
大体思路如下:
(1)拿到routes: this.router.options.routes
const routes = [
{
path: '/',
component: () => import('../views/Home'),
meta: {title: "组卷管理"},
children: [
{
path: 'hand',
component: () => import('../views/Home'),
meta: {title: "手动组卷"}
},
{
path: 'mid',
component: () => import('../views/Home'),
meta: {title: "自动组卷"}
},
]
},
{
path: '/exam',
component: () => import('../views/Home'),
meta: {title: "考试管理"},
children: [
{
path: 'mid',
component: () => import('../views/Home'),
meta: {title: "期中考试"}
},
{
path: 'final',
component: () => import('../views/Home'),
meta: {title: "期末考试"}
},
{
path: 'else',
component: () => import('../views/Home'),
meta: {title: "其他考试"},
children: [
{
path: 'unit',
component: () => import('../views/Home'),
meta: {title: "单元测验"}
},
{
path: 'daily',
component: () => import('../views/Home'),
meta: {title: "日常作业"}
},
]
},
]
}
]
为了方便后续理解,我简化下结构就是
let routes = [
{ path, meta, children:[{path,meta}, {path,meta}, ...] },
{ path, meta, chidren: [ {path, meta, children: [...]} ] }
]
我们需要 path 作为 router-link 的目标值,
需要 meta 中的 自定义title 作为菜单项显示的文字,
需要 children.length 判断该节点是否为叶子结点,
需要 children 进行深搜
(2)创建菜单项组件 MyMenu(根节点)、SubMenu(非叶子节点)、MenuItem(叶子节点)
MyMenu 对应一个根节点,是无需有内容的,可以搭配 ElementUI 的 < el-menu > 使用
<template>
<div class="menu">
<el-menu>
// todo
</el-menu>
</div>
</template>
接着我们可以自顶下下进行思考,用我们现在有的条件去看看 我们需要什么样的 SubMenu 和 MenuItem
先看简单 的 MenuItem, 对应叶子节点
<template>
<div>
<el-menu-item :index="idx">
<router-link tag="div" :to="resolvePath(cur.path)" >{{cur.meta.title}}-{{resolvePath(cur.path)}}</router-link>
</el-menu-item>
</div>
</template>
接着是 非叶子节点 SubMenu
<template>
<div>
<el-submenu :index="idx">
<template slot="title">
<i class="el-icon-location"></i>
<span>{{cur.meta.title}}-{{resolvePath(cur.path)}}</span>
</template>
<div>
<template v-for="(item, num) of cur.children">
<sub-menu v-if="item.children && item.children.length>0" :cur="item" :pre_url="resolvePath(cur.path)" :key="item.path" :idx="getIdx(num)"></sub-menu>
<menu-item v-else :cur="item" :pre_url="resolvePath(cur.path)" :key="item.path" :idx="getIdx(num)"></menu-item>
</template>
</div>
</el-submenu>
</div>
</template>
剩下的还有 index问题收缩问题,还有父子同步激活的问题,以及如何使用 DOM 实现不用Vue,后续说明
最后的效果是这个样的