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.效果图
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。