demo 地址:https://gitee.com/shjin/menu_…
1. 创立 vue
我的项目
vue create menu_demo
2. 装置ant-design-vue
yarn add ant-design-vue
3.main.js
文件引入ant-design-vue
import Antd from 'ant-design-vue';
import 'ant-design-vue/dist/antd.css';
Vue.use(Antd);
4. 菜单 index.js
import Menu from "ant-design-vue/es/menu";
import Icon from "ant-design-vue/es/icon";
const {Item, SubMenu} = Menu;
export default {
name: "SMenu",
props: {
menu: {
type: Array,
required: true
},
theme: {
type: String,
required: false,
default: "light"
},
mode: {
type: String,
required: false,
default: "inline"
},
collapsed: {
type: Boolean,
required: false,
default: false
},
},
data() {
return {openKeys: [],
cachedOpenKeys: [],
selectedKeys:['user1']
};
},
computed: {
rootSubmenuKeys: vm => {const keys = [];
vm.menu.forEach(item => keys.push(item.path));
return keys;
}
},
mounted() {this.updateMenu();
},
watch: {collapsed(val) {if (val) {this.cachedOpenKeys = this.openKeys.concat();
this.openKeys = [];} else {this.openKeys = this.cachedOpenKeys;}
},
$route: function() {this.updateMenu();
}
},
methods: {
// select menu item
onOpenChange(openKeys) {
// 在程度模式下时执行,并且不再执行后续
if (this.mode === "horizontal") {
this.openKeys = openKeys;
return;
}
// 非程度模式时
const latestOpenKey = openKeys.find(key => !this.openKeys.includes(key));
if (!this.rootSubmenuKeys.includes(latestOpenKey)) {this.openKeys = openKeys;} else {this.openKeys = latestOpenKey ? [latestOpenKey] : [];}
},
updateMenu() {const routes = this.$route.matched.concat();
const {hidden} = this.$route.meta;
if (routes.length >= 3 && hidden) {routes.pop();
this.selectedKeys = [routes[routes.length - 1].path];
} else {this.selectedKeys = [routes.pop().path];
}
const openKeys = [];
if (this.mode === "inline") {
routes.forEach(item => {openKeys.push(item.path);
});
}
//update-begin-author:taoyan date:20190510 for:online 表单菜单点击开展的一级目录不对
if (!this.selectedKeys || this.selectedKeys[0].indexOf(":") < 0) {
this.collapsed
? (this.cachedOpenKeys = openKeys)
: (this.openKeys = openKeys);
}
//update-end-author:taoyan date:20190510 for:online 表单菜单点击开展的一级目录不对
},
// render
renderItem(menu) {if (!menu.hidden) {
return menu.children && !menu.alwaysShow
? this.renderSubMenu(menu)
: this.renderMenuItem(menu);
}
return null;
},
renderMenuItem(menu) {let props = { to: { name: menu.name} };
const attrs = {target: menu.target};
return (<Item {...{ key: menu.key}}>
<div
{...{ props, attrs}}
>
{this.renderIcon(menu.icon)}
<span>{menu.title}</span>
</div>
</Item>
);
},
renderSubMenu(menu) {const itemArr = [];
if (!menu.alwaysShow) {menu.children.forEach(item => itemArr.push(this.renderItem(item)));
}
return (<SubMenu {...{ key: menu.key}}>
<span slot="title">
{this.renderIcon(menu.icon)}
<span>{menu.title}</span>
</span>
{itemArr}
</SubMenu>
);
},
renderIcon(icon) {if (icon === "none" || icon === undefined) {return null;}
const props = {};
typeof icon === "object" ? (props.component = icon) : (props.type = icon);
return <Icon {...{ props}} />;
}
},
render() {const { mode, theme, menu} = this;
const props = {
mode: mode,
theme: theme,
openKeys: this.openKeys
};
const on = {
select: obj => {
this.selectedKeys = obj.selectedKeys;
this.$emit("select", obj);
},
openChange: this.onOpenChange
};
const menuTree = menu.map(item => {if (item.hidden) {return null;}
return this.renderItem(item);
});
return (<Menu vModel={this.selectedKeys} {...{ props, on: on}}>
{menuTree}
</Menu>
);
}
};
5. 联合应用
<template>
<div>
<a-layout id="components-layout-demo-custom-trigger">
<a-layout-sider
v-model="collapsed"
:trigger="null"
collapsible
:style="{
overflow: 'auto',
height: '100vh',
position: 'fixed',
left: 0,
zIndex: 2,
}"
>
<s-menu
class="my-menu"
:menu="treeData"
theme="dark"
ref="sMenu"
mode="inline"
:selectedKeys="selectedKeys"
@select="onSelect"
:collapsed="collapsed"
collapseible
>
</s-menu>
</a-layout-sider>
<a-layout :style="{marginLeft: collapsed ?'80px':'200px'}">
<a-layout-header
style="background: #fff; padding: 0,"
:style="{position:'fixed', zIndex: 1, width:'100%'}"
>
<a-icon
class="trigger"
:type="collapsed ?'menu-unfold':'menu-fold'"@click="() => (collapsed = !collapsed)"
/>
</a-layout-header>
<div
:style="{
position: 'fixed', zIndex: 1, width: '100%',
background: '#fff',
top:'70px'
}"
>
<a-tabs
v-model="activeKey"
@prevClick="callback"
@nextClick="callback"
@tabClick="menuClick"
type="card"
>
<a-tab-pane v-for="(pane, index) in menuList" :key="pane.key">
<span slot="tab" class="item-pane">
{{pane.title}}
<a-icon
v-if="index !== 0"
type="close"
class="pane-close"
@click.stop="closeMenu(index, pane)"
/>
</span>
</a-tab-pane>
</a-tabs>
</div>
<a-layout-content
:style="{
margin: '134px 16px 24px 16px',
padding: '24px',
background: '#fff',
minHeight: '280px',
height: 'calc(100vh - 160px)',
overflow: 'auto',
}"
>
<div style="height:600px">Content</div>
</a-layout-content>
</a-layout>
</a-layout>
</div>
</template>
<script>
import SMenu from "@/components/index";
export default {components: { SMenu},
data() {
return {
collapsed: false,
activeKey: "user1", // 以后菜单 key
expandedKeys: [],
selectedKeys: ["user1"],
autoExpandParent: true,
menuList: [{key: "user1", title: "用户 1"}],
treeData: [
{
title: "用户 1",
key: "user1",
icon: "user",
},
{
title: "媒体",
key: "video-camera",
icon: "video-camera",
children: [
{
title: "上传",
key: "upload",
},
{
title: "下载",
key: "download",
children: [
{
title: "下载 2",
key: "download2",
},
],
},
],
},
],
};
},
methods: {
// 抉择树节点
onSelect(event) {
let key = event.key;
this.activeKey = key;
this.selectedKeys = [key];
let title = this.getTitle(this.treeData, key);
let filterMenu = this.menuList.filter((menu) => menu.key == key);
if (!filterMenu.length) this.menuList.push({key, title});
},
getTitle(data, value) {
let title;
for (let i = 0; i < data.length; i++) {let item = data[i];
if (item && item.key == value) {title = item.title;} else if (item.children && item.children.length) {if (this.getTitle(item.children, value)) {title = this.getTitle(item.children, value);
}
}
}
return title;
},
menuClick(val) {this.selectedKeys = [val];
this.$refs.sMenu.selectedKeys = this.selectedKeys;
},
// 敞开标签
closeMenu(index, item) {this.menuList.splice(index, 1);
if (this.activeKey == item.key) {this.activeKey = this.menuList[index - 1].key;
this.selectedKeys = [this.activeKey];
}
console.log(item);
},
callback(val) {console.log(val);
},
},
};
</script>
<style scoped>
.ant-layout-header {padding: 0;}
#components-layout-demo-custom-trigger .trigger {
font-size: 18px;
line-height: 64px;
padding: 0 24px;
cursor: pointer;
transition: color 0.3s;
}
#components-layout-demo-custom-trigger .trigger:hover {color: #1890ff;}
</style>
6. 效果图