乐趣区

关于vue.js:vueantdesignvue实现导航菜单循环遍历

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

退出移动版