【Ant Design Vue 】之Menu選單

2021-03-12 12:00:50

版本ant-design-vue: "^1.7.4",

常用屬性

屬性說明預設值
mode選單型別,現在支援垂直、水平、和內嵌模式三種vertical
inlineCollapsedinline 時選單是否收起狀態
theme主題顏色(light/dark)light
openKeys(.sync)當前展開的 SubMenu 選單項 key 陣列
defaultOpenKeys初始展開的 SubMenu 選單項 key 陣列
selectedKeys(v-model)當前選中的選單項 key 陣列
defaultSelectedKeys初始選中的選單項 key 陣列

說明
defaultSelectedKeys 是預設選中的keya-menu-item上繫結的key),被選中會有高亮的顯示效果;selectedKeys 也是一樣的作用,不要同時使用,區別在於如果只希望指定一個初始化的選單選項就使用defaultSelectedKeys,如果需要通過自己修改資料來選中選單的選中項就使用selectedKeys
openKeysdefaultOpenKeys也是同理)

常用事件

openChangeMenu的事件,SubMenu 展開/關閉的回撥

遞迴巢狀多級選單

若只有兩級選單則直接使用v-forv-if指令即可完成;若選單級數≥3則需要使用函數式元件。具體原因官網已經做了說明:

Before v2.0, 因元件內部會動態更改a-sub-menu的屬性,如果拆分成單檔案,無法將屬性掛載到a-sub-menu上,你需要自行宣告屬性並掛載。為了方便,避免屬性的宣告,我們推薦使用函數式元件。

程式碼
App.vue (測試就隨便在App.vue裡寫了)

<template>
    <div id="app">
        <div style="width: 256px">
            <a-button type="primary" style="margin-bottom: 16px" @click="toggleCollapsed">
            <a-icon :type="collapsed ? 'menu-unfold' : 'menu-fold'" />
            </a-button>
            <a-menu
                :defaultSelectedKeys="[$route.path]"
                :openKeys="openKeys"
                mode="inline"
                theme="dark"
                :inline-collapsed="collapsed"
                @openChange="onOpenChange"
                @click="menuClick"
            >
                <template v-for="item in list">
                    <a-menu-item v-if="!item.children" :key="item.path">
                        <a-icon type="pie-chart" />
                        <span>{{ item.title }}</span>
                    </a-menu-item>
                    <sub-menu v-else :key="item.path" :menu-info="item" />
                </template>
            </a-menu>
        </div>
        <router-view/>
    </div>
</template>

<script>
import { Menu } from 'ant-design-vue';
const SubMenu = {
  template: `
      <a-sub-menu :key="menuInfo.key" v-bind="$props" v-on="$listeners">
        <span slot="title">
          <a-icon type="mail" /><span>{{ menuInfo.title }}</span>
        </span>
        <template v-for="item in menuInfo.children">
          <a-menu-item v-if="!item.children" :key="item.path">
            <a-icon type="pie-chart" />
            <span>{{ item.title }}</span>
          </a-menu-item>
          <sub-menu v-else :key="item.path" :menu-info="item" />
        </template>
      </a-sub-menu>
    `,
  name: 'SubMenu',
  // must add isSubMenu: true 此項必須被定義
  isSubMenu: true,
  props: {
    // 解構a-sub-menu的屬性,也就是文章開頭提到的為什麼使用函數式元件
    ...Menu.SubMenu.props,
    // Cannot overlap with properties within Menu.SubMenu.props
    menuInfo: {
      type: Object,
      default: () => ({}),
    },
  },
};

export default {
    name: "App",
    components: {
        'sub-menu': SubMenu,
    },
    data() {
        return {
            collapsed: false,
            openKeys: [],
            rootSubmenuKeys: ['/user'],
            list: [
                {
                    key: '1',
                    title: '資訊管理',
                    path: '/info',
                },
                {
                    key: '2',
                    title: '使用者管理',
                    path: '/user',
                    children: [
                        { 
                            key: '2.1',
                            title: '後臺使用者',
                            path: '/adminUser',
                            children: [
                                { 
                                    key: '2.1.1',
                                    title: '新增使用者',
                                    path: '/addAdminUser',
                                    children: [
                                        {
                                            key: '2.1.1。1',
                                            title: '使用者xx',
                                            path: '/addAdminUserXX',
                                        }
                                    ]
                                }
                            ]
                        },
                        { 
                            key: '2.2',
                            title: '前臺使用者',
                            path: '/frontUser',
                        }
                    ]
                }
            ],
        };
    },
    created(){
        const openKeys = window.sessionStorage.getItem('openKeys')
        if(openKeys){
            this.openKeys = JSON.parse(openKeys)
        }
    },
    methods: {
        toggleCollapsed() {
            this.collapsed = !this.collapsed;
        },
        onOpenChange(openKeys) {
            // 將當前開啟的父級選單存入快取中
            window.sessionStorage.setItem('openKeys', JSON.stringify(openKeys))
            //  控制只開啟一個
            const latestOpenKey = openKeys.find(key => this.openKeys.indexOf(key) === -1);
            if (this.rootSubmenuKeys.indexOf(latestOpenKey) === -1) {
                this.openKeys = openKeys;
            } else {
                this.openKeys = latestOpenKey ? [latestOpenKey] : [];
            }
        },
        menuClick({key}) {
            // 獲取到當前的key,並且跳轉
            this.$router.push({
                path: key
            })
        },
    }
};
</script>

<style>
#app {
  font-family: Avenir, Helvetica, Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  padding: 50px;
}
</style>

這裡省略了router設定,相信在座的各位也會!(不會的底下留言,包教包會!)

如果vue報編譯錯誤You are using the runtime-only build of Vue,可以在vue的組態檔里加一行runtimeCompiler: true,重新執行即可。

如果點選同一個選單報錯了NavigationDuplicated: Avoided redundant navigation to current location,需要修改下Router設定(router/index.js):

const originalPush = Router.prototype.push
Router.prototype.push = function push(location) {
    return originalPush.call(this, location).catch(err => err)
}

效果

在這裡插入圖片描述
自動渲染多級巢狀選單;重新整理會儲存選中的選單;點選選單,收起其他展開的所有選單。