ant-design-vue 动态生成导航菜单(1~2级)
ant-design-vue 动态生成导航菜单(1~2级)
·
由于近来公司业务繁忙,以至于没时间去接着做antd的项目。emmm…后面应该还会忙些时间!
antd的路由导航还是有些坑的,对习惯了element的小伙伴来说不那么理想。这里先记录一下如何通过路由来动态生成1~2级导航菜单了(之后会出三级及以上导航菜单爬坑日志)。注: 此文为过渡文,没怎么上心,表达不明之处还请见谅,另外,欢迎打扰~~~~项目在线地址 (有用的话,记得给个start哦)
- antd的a-menu标签内部不能使用除template外的其他任何标签包裹 a-menu-item 以及 a-sub-menu标签,一旦使用就会报错!也因此没法组件化二级菜单(这里先不讲函数式组件)
- 既然是动态生成二级导航菜单,当然就不能使用定义路由、子路由的数组来维护,太繁琐,每次新增一个路由还得手动去添加。这样根本就算不得动态了。在这里博主参考的是花裤衩大佬的vue-element-admin开源项目所使用的方法。通过在定义路由的时候同时写入hidden(是否加入动态生成的导航菜单)以及meta(动态生成title及icon),代码如下:
{
path: '/',
component: Layout,
redirect: '/dashboard',
children: [
{
path: 'dashboard',
name: 'Home',
component: () => import('@/views/dashboard/index'),
meta: { title: 'Dashboard', icon: 'user' }
}
]
}
- 导航菜单(这里在后期有更新(在做三级及以上路由的时候有大幅更新),先放个最初版本的,在下一篇文章会贵出最终版)
<a-menu theme="dark" mode="inline" :selected-keys="currentSelectMenu" :open-keys="openKeys" @click="menuClick" @openChange="onOpenChange">
<template v-for="item in routers">
<template v-if="!item.hidden && item.children">
<!-- 只有一个子菜单: 一级菜单 -->
<a-menu-item v-if="item.children.length === 1" :key="item.path === '/' ? `${item.path}${item.children[0].path}`: `${item.path}/${item.children[0].path}`">
<a-icon :type="item.children[0] && item.children[0].meta && item.children[0].meta.icon" />
<router-link style="display: inline-block" :to="{path: item.path === '/' ? `${item.path}${item.children[0].path}` : `${item.path}/${item.children[0].path}`}">
{{ generateTitle(item.children[0].meta.title) }}
</router-link>
</a-menu-item>
<!-- submenu -->
<a-sub-menu v-else :key="item.path">
<span slot="title">
<a-icon :type="item.meta && item.meta.icon" />
<span v-if="item.meta">{{ generateTitle(item.meta.title) }}</span>
</span>
<template v-for="subItem in item.children">
<a-menu-item v-if="!subItem.children" :key="item.path + '/' + subItem.path">
<a-icon v-if="subItem.meta.icon" :type="subItem.meta && subItem.meta.icon" />
<router-link style="display: inline-block" :to="item.path + '/' + subItem.path">
{{ generateTitle(subItem.meta.title) }}
</router-link>
</a-menu-item>
</template>
</a-sub-menu>
</template>
</template>
</a-menu>
这里涉及到的a-menu属性啥的就不详细赘述了,官方文档挺好的(主要是表达能力着实不行…),这里说一下所用到的属性及事件吧。
- selected-keys: 当前选中的菜单项,值的类型为字符串数组。这里主要用于刷新界面后保持选中的状态;
// 当前选中的菜单项(这里直接返回path即可)
currentSelectMenu() {
return [this.$route.path]
}
open-keys:当前展开的 SubMenu 菜单项 key 数组,这里的key数组必须与父节点菜单的key值相对应。实现openKeys与父节点菜单的key的方法有很多,最初采用的是将其存入浏览器的sessionStorage(有些麻烦,后期在做三级菜单的时候移除了)。openChange:SubMenu 展开/关闭的回调,主要是为了控制当前submenu菜单是否展开/关闭;
// 通过菜单栏的点击事件menuClick将当前菜单的key存入sessionStorage
menuClick({ item, key, keyPath }) {
// length为1则说明没有子菜单
if (keyPath.length === 1) {
this.openKeys = []
window.sessionStorage.clear()
} else window.sessionStorage.setItem('open-menu-key', keyPath.pop()) // 将副路由存入sessionStorage,展开激活submenu菜单
},
// 在created生命周期获取,初始化展开submenu
const openKeys = window.sessionStorage.getItem('open-menu-key')
if (openKeys) this.openKeys = [openKeys]
// openChange:SubMenu 展开/关闭的回调,主要是为了控制当前submenu菜单是否展开/关闭
// 子菜单展开/关闭的回调
onOpenChange(openKeys) {
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
this.openKeys = this.rootSubmenuKeys.indexOf(latestOpenKey) === -1 ? openKeys : latestOpenKey ? [latestOpenKey] : []
}
最后,附上全部代码
<template>
<div class="sidebar-container">
<a-layout-sider v-model="isCollapsed" :trigger="null" collapsible>
<div class="logo" />
<a-menu theme="dark" mode="inline" :selected-keys="currentSelectMenu" :open-keys="openKeys" @click="menuClick" @openChange="onOpenChange">
<template v-for="item in routers">
<template v-if="!item.hidden && item.children">
<!-- menu -->
<a-menu-item v-if="item.children.length === 1" :key="item.path === '/' ? `${item.path}${item.children[0].path}`: `${item.path}/${item.children[0].path}`">
<a-icon :type="item.children[0] && item.children[0].meta && item.children[0].meta.icon" />
<router-link style="display: inline-block" :to="{path: item.path === '/' ? `${item.path}${item.children[0].path}` : `${item.path}/${item.children[0].path}`}">
{{ generateTitle(item.children[0].meta.title) }}
</router-link>
</a-menu-item>
<!-- submenu -->
<a-sub-menu v-else :key="item.path">
<span slot="title">
<a-icon :type="item.meta && item.meta.icon" />
<span v-if="item.meta">{{ generateTitle(item.meta.title) }}</span>
</span>
<template v-for="subItem in item.children">
<a-menu-item v-if="!subItem.children" :key="item.path + '/' + subItem.path">
<a-icon v-if="subItem.meta.icon" :type="subItem.meta && subItem.meta.icon" />
<router-link style="display: inline-block" :to="item.path + '/' + subItem.path">
{{ generateTitle(subItem.meta.title) }}
</router-link>
</a-menu-item>
</template>
</a-sub-menu>
</template>
</template>
</a-menu>
</a-layout-sider>
</div>
</template>
<script>
// 国际化导航菜单title
import { generateTitle } from './breadcrumb/index.js'
export default {
name: 'SubMenu',
props: {
collapsed: [Boolean],
routers: {
type: Array,
default: () => []
}
},
data() {
return {
isCollapsed: false,
onlyOneChild: null,
openKeys: [''],
rootSubmenuKeys: ['/form', '/about'] // submenu数组
}
},
computed: {
// 当前选中的菜单项
currentSelectMenu() {
return [this.$route.path]
},
router() {
return this.$route.path
}
},
watch: {
collapsed: {
handler: function(val) {
this.isCollapsed = val
}
}
},
created() {
// 获取当前副路由(需要展开)
const openKeys = window.sessionStorage.getItem('open-menu-key')
if (openKeys) this.openKeys = [openKeys]
},
methods: {
generateTitle,
// 点击菜单触发事件
menuClick({ item, key, keyPath }) {
// length为1则说明没有子菜单
if (keyPath.length === 1) {
this.openKeys = []
window.sessionStorage.clear()
} else window.sessionStorage.setItem('open-menu-key', keyPath.pop()) // 将副路由存入sessionStorage,展开激活submenu菜单
},
// 子菜单展开/关闭的回调
onOpenChange(openKeys) {
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
this.openKeys = this.rootSubmenuKeys.indexOf(latestOpenKey) === -1 ? openKeys : latestOpenKey ? [latestOpenKey] : []
}
}
}
</script>
<style lang="less" scoped>
.logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
}
</style>
更多推荐
已为社区贡献8条内容
所有评论(0)