ant-design-vue 导航菜单实现3级及以上(函数式组件)
ant-design-vue 导航菜单实现3级及以上(函数式组件)
·
emmm…发现前面一篇我自己在没做过的情况下也看不懂((/ω\))。3级及以上导航菜单的实现说到底也不会很难,就是交互(菜单展开与否)比较烦人,在这里就稍微提一下需要注意的东西。推荐大家还是直接clone一下项目,查看log信息吧。 在线demo
按照官网信息,根据项目来进行一定的处理,最终的code如下:
import { generateTitle } from './breadcrumb/index.js'
import { Menu } from 'ant-design-vue'
import path from 'path'
// 函数式组件
const SubMenu = {
template: `
<a-sub-menu :key="menuInfo.path" v-bind="$props" v-on="$listeners">
<span slot="title" class="menu-title">
<a-icon :type="menuInfo.meta && menuInfo.meta.icon" />
<span v-if="menuInfo.meta">{{ generateTitle(menuInfo.meta.title) }}</span>
</span>
<template v-for="item in menuInfo.children">
<a-menu-item v-if="!item.children" :key="resovePath(item.path)">
<router-link style="display: inline-block;" :to="resovePath(item.path)">
{{ generateTitle(item.meta.title) }}
</router-link>
</a-menu-item>
<sub-menu v-else :key="item.path" :menu-info="item" :base-route="resovePath(item.path)" />
</template>
</a-sub-menu>
`,
name: 'SubMenu',
// must add isSubMenu: true
isSubMenu: true,
props: {
...Menu.SubMenu.props,
// Cannot overlap with properties within Menu.SubMenu.props
menuInfo: {
type: Object,
default: () => ({})
},
baseRoute: {
type: String,
default: ''
}
},
methods: {
generateTitle,
resovePath(item) {
return path.resolve(this.baseRoute, item)
}
}
}
export default SubMenu
在这里需要用到node的path模块来对路由hash进行拼接(鬼知道我掉了多少头发才想到这个方法的…)。每次传入的baseRouter即父节点的path,将path一个个拼接起来就是完整的path。
上一篇说到判断优化、多级路由啥的。推荐大家将项目clone下来根据log一步步查看吧,都过去好几天了,懒得再reset回去看…我把最终的code贴出来吧,有兴趣的可以研究下
<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">
<!-- menu -->
<a-menu-item v-if="hasOneChildren(item.children)" :key="item.redirect">
<a-icon :type="item.children[0] && item.children[0].meta && item.children[0].meta.icon" />
<span class="menu-title">
<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>
</span>
</a-menu-item>
<!-- submenu -->
<sub-menu v-else :key="item.path" :menu-info="item" :base-route="item.path" />
</template>
</template>
</a-menu>
</a-layout-sider>
</div>
</template>
<script>
import { generateTitle } from './breadcrumb/index.js'
import SubMenu from './subMenu'
export default {
components: {
SubMenu
},
props: {
collapsed: [Boolean],
routers: {
type: Array,
default: () => []
},
parentNodeList: {
type: Array,
default: () => []
}
},
data() {
return {
isCollapsed: false,
onlyOneChild: null,
openKeys: []
}
},
computed: {
// 当前选中的菜单项
currentSelectMenu() {
return [this.$route.path]
},
router() {
return this.$route.path
}
},
watch: {
collapsed: {
handler: function(val) {
this.isCollapsed = val
}
}
},
created() {
const openKeysArr = (this.$route.path).split('/')
openKeysArr.shift()
openKeysArr[0] = '/' + openKeysArr[0]
openKeysArr.forEach((item, index) => {
this.openKeys.unshift(item)
})
},
methods: {
generateTitle,
// 点击菜单触发事件
menuClick({ item, key, keyPath }) {
// length为1则说明没有子菜单
keyPath.length === 1 ? this.openKeys = [] : ''
},
// 子菜单展开/关闭的回调
onOpenChange(openKeys) {
const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1)
this.openKeys = this.parentNodeList.indexOf(latestOpenKey) === -1 ? openKeys : latestOpenKey ? [latestOpenKey] : []
},
// 单个子节点
hasOneChildren(item) {
return !item.some(menu => menu.children) && item.length === 1
}
}
}
</script>
<style lang="less" scoped>
.logo {
height: 32px;
background: rgba(255, 255, 255, 0.2);
margin: 16px;
}
.menu-title {
display: inline-block;
width: 85%;
a {
display: inline-block;
width: 100%;
color: #ccc;
&:hover {
color: #fff;
}
}
}
</style>
更多推荐
已为社区贡献8条内容
所有评论(0)