本記事では以下のコードを参考にさせていただきました。
[Feature Request] Nested menus · Issue #1877 · vuetifyjs/vuetify
What will it allow you to do that you can't do today? Create nested menus according to MD spec How will it make current work-arounds straightforward? A current ...
完成形イメージ
上のような、ネストしたメニューを作ります。
好きなところにDividerをつけたり、それぞれクリックしたときのアクションなどを定義することができます。
サンプルコード
以下、コンポーネント化したネストメニューです。
ご自身に合うようにカスタムしてください。
<template>
<v-menu :offset-x='isOffsetX' :offset-y='isOffsetY' :open-on-hover='isOpenOnHover' :transition='transition'>
<template v-slot:activator="{ on }">
<v-btn v-if='icon' :color='color' v-on="on"><v-icon>{{ icon }}</v-icon></v-btn>
<v-list-item v-else-if='isSubMenu' class='d-flex justify-space-between' v-on="on">
{{ name }}<v-icon>far fa-chevron-right</v-icon>
</v-list-item>
<v-btn v-else :color='color' v-on="on" text tile>{{ name }}</v-btn>
</template>
<v-list>
<template v-for="(item, index) in menuItems">
<v-divider v-if='item.isDivider' :key='index' />
<nested-menu v-else-if='item.menu' :key='index' :name='item.name' :menu-items='item.menu' @nested-menu-click='emitClickEvent'
:is-open-on-hover=false :is-offset-x=true :is-offset-y=false :is-sub-menu=true
/>
<v-list-item v-else :key='index' @click='emitClickEvent(item)'>
<v-list-item-title>{{ item.name }}</v-list-item-title>
</v-list-item>
</template>
</v-list>
</v-menu>
</template>
<script>
export default {
name: 'NestedMenu',
props: {
name: String,
icon: String,
menuItems: Array,
color: { type: String, default: 'secondary' },
isOffsetX: { type: Boolean, default: false },
isOffsetY: { type: Boolean, default: true },
isOpenOnHover: { type: Boolean, default: false },
isSubMenu: { type: Boolean, default: false },
transition: { type: String, default: 'scale-transition' }
},
methods: {
emitClickEvent (item) {
// this.closeAllMenus() // Theoretically, create a method that does this as a workaround
this.$emit('nested-menu-click', item)
}
}
}
</script>
以下、親コンポーネントになります。
fileMenuItemsという配列の中身によってメニューの構成が変わります。
<template>
<v-app>
<v-main>
<nested-menu name='ネストしたメニューを開く' :menu-items='fileMenuItems' @nested-menu-click='onMenuItemClick' />
</v-main>
</v-app>
</template>
<script>
import NestedMenu from './components/NestedMenu.vue';
export default {
name: 'App',
components: {
NestedMenu
},
data: () => ({
fileMenuItems: [
{ name: 'メニュー1', action: () => { console.log('menu-item-1') } },
{ isDivider: true },
{ name: 'メニュー2' },
{
name: 'サブメニュー1',
menu: [
{ name: '1.1' },
{ name: '1.2' },
{
name: 'サブメニュー2',
menu: [
{ name: '2.1' },
{ name: '2.2' },
{
name: 'サブメニュー3',
menu: [
{ name: '3.1' },
{ name: '3.2' },
{
name: 'サブメニュー4',
menu: [
{ name: '4.1'},
{ name: '4.2' },
{ name: '4.3' }
]
}
]
}
]
}
]
},
{ name: 'メニュー3' },
{ isDivider: true },
{ name: 'メニュー4', action: () => { console.log('menu-item-4') } },
{ name: 'メニュー5', action: () => { console.log('menu-item-5') } }
]
}),
methods: {
onMenuItemClick (item) {
console.log(`onMenuItemClick(), item=${item}`)
if (item.action) {
item.action()
}
}
}
};
</script>
クリック時のアクションは、
action: () => { console.log('menu-item-1') }
といったように定義します。
クリック時にサブメニューを開く場合は、以下のようにmenu配列を指定します。
menu: [
{ name: '4.1'},
{ name: '4.2' },
{ name: '4.3' }
]
また、
{ isDivider: true },
とすることでDivider(区切り線)を表示させることができます。
まとめ
以上になります。
コンポーネント化することでシンプルに使えるようになっていいですね!
コメント