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.效果图