Vuetify 3 v-list-group – 在打开组时折叠其他子菜单

huangapple go评论53阅读模式
英文:

Vuetify 3 v-list-group - collapse other sub-menus when opening group

问题

I'm using Vuetify 3 and I'm trying to implement a collapsible vertical menu inside the Vuetify navigation drawer using the v-list-group component. I need the currently expanded menu item to collapse when another menu item is clicked to expand (Accordion behavior). I've created the menu list, but the accordion effect does not work as expected.

Template:

<v-navigation-drawer
	v-model="drawer"
	temporary
	location="right"
	theme="dark"
>
	<v-list density="compact">
		<v-list-group v-model="item.active" v-for="item in menuItems">
			<template v-slot:activator="{ props }">
				<v-list-item
					:key="item.title"
					v-bind="props"
					:title="item.title"
				></v-list-item>
			</template>

			<v-list-item
				v-for="subMenu in item.subMenuItems"
				:key="subMenu"
				:title="subMenu"
			></v-list-item>
		</v-list-group>
	</v-list>
</v-navigation-drawer>

Script:

<script setup>
const menuItems = ref([
	{
		title: "Menu Item 1",
		active: false,
		subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
	},
	{
		title: "Menu Item 2",
		active: false,
		subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
	},
	{
		title: "Menu Item 3",
		active: false,
		subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
	}
])
</script>

In Vuetify 2, I could assign a variable to the v-model of v-list-group component, but this does not work with Vuetify 3 (Changing the value does not change the collapse/expand state).

The v-list-group component does not contain an is-open prop to manually modify its state (there is an isOpen flag which is passed to the activator slot, but it is read-only).

英文:

I'm using Vuetify 3 and I'm trying to implement a collapsible vertical menu inside the Vuetify navigation drawer using the v-list-group component. I need the currently expanded menu item to collapse when another menu item is clicked to expand (Accordion behavior). I've created the menu list, but the accordion effect does not work as expected.

Template:

&lt;v-navigation-drawer
		v-model=&quot;drawer&quot;
		temporary
		location=&quot;right&quot;
		theme=&quot;dark&quot;
	&gt;
		&lt;v-list density=&quot;compact&quot;&gt;
			&lt;v-list-group v-model=&quot;item.active&quot; v-for=&quot;item in menuItems&quot;&gt;
				&lt;template v-slot:activator=&quot;{ props }&quot;&gt;
					&lt;v-list-item
						:key=&quot;item.title&quot;
						v-bind=&quot;props&quot;
						:title=&quot;item.title&quot;
					&gt;&lt;/v-list-item&gt;
				&lt;/template&gt;

				&lt;v-list-item
					v-for=&quot;subMenu in item.subMenuItems&quot;
					:key=&quot;subMenu&quot;
					:title=&quot;subMenu&quot;
				&gt;&lt;/v-list-item&gt;
			&lt;/v-list-group&gt;
		&lt;/v-list&gt;
	&lt;/v-navigation-drawer&gt;

Script:

&lt;script setup&gt;

const menuItems = ref([
	{
		title: &quot;Menu Item 1&quot;,
		active: false,
		subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
	},
	{
		title: &quot;Menu Item 2&quot;,
		active: false,
		subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
	},
	{
		title: &quot;Menu Item 3&quot;,
		active: false,
		subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
	}
])

&lt;/script&gt;

In Vuetify 2, I could assign a variable to the v-model of v-list-group component, but this does not work with Vuetify 3 (Changing the value does not change the collapse/expand state).

The v-list-group component does not contain an is-open prop to manually modify its state (there is an isOpen flag which is passed to the activator slot, but it is read-only).

答案1

得分: 3

以下是代码部分的翻译:

<v-list
  :opened="opened"
  @update:opened="newOpened => opened = newOpened.slice(-1)"
>
  <v-list-group
    v-for="item in menuItems"
    :key="item.title"
    :value="item"
  >
  ...
const {
  createApp,
  ref,
  computed
} = Vue;
const {
  createVuetify
} = Vuetify
const vuetify = createVuetify()
createApp({
  setup() {
    const menuItems = ref([{
        title: "Menu Item 1",
        active: false,
        subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
      },
      {
        title: "Menu Item 2",
        active: true,
        subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
      },
      {
        title: "Menu Item 3",
        active: false,
        subMenuItems: ["Sub Menu Item 1", "Sub Menu Item 2", "Sub Menu Item 3"]
      }
    ])
    const opened = ref([])

    return {
      opened,
      drawer: ref(true),
      menuItems,
    }
  }
}).use(vuetify).mount('#app')
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/vuetify@3.1.9/dist/vuetify.min.css" />
<link href="https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css" rel="stylesheet">
<div id="app" class="d-flex justify-center">
  <v-app>
    <v-card>
      <v-layout>

        <v-navigation-drawer v-model="drawer" temporary>
          <v-list density="compact" :opened="opened" @update:opened="opened = $event.slice(-1)">
            <v-list-group v-for="item in menuItems" :key="item.title" :value="item">
              <template v-slot:activator="{props, isOpen}">
                <v-list-item
                    v-bind="props"
                    :key="item.title" 
                    :title="item.title"
                ></v-list-item>
              </template>

              <v-list-item v-for="subMenu in item.subMenuItems" :key="subMenu" :title="subMenu"></v-list-item>
            </v-list-group>
          </v-list>
        </v-navigation-drawer>

        <v-main style="height: 500px;">

        </v-main>
      </v-layout>
    </v-card>
  </v-app>
</div>
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vuetify@3.1.9/dist/vuetify.min.js"></script>
英文:

Yup, looks like that was changed, you need to do it using the surrounding v-list now.

The :opened property of v-list is an array that corresponds to which groups are opened. Which values are put into the list is determined by the :value property of v-list-group. To have at most one group open, you can listen to the @update:opened event and fix the list accordingly.

So with a ref opened = ref([]), you can do:

&lt;v-list
  :opened=&quot;opened&quot;
  @update:opened=&quot;newOpened =&gt; opened = newOpened.slice(-1)&quot;
&gt;
  &lt;v-list-group
    v-for=&quot;item in menuItems&quot;
    :key=&quot;item.title&quot;
    :value=&quot;item&quot;
  &gt;
  ...

With @update:opened=&quot;opened = $event.slice(-1)&quot;, all but the last element will be removed when the list is updated. This will close all groups except the one clicked last.

The :value=&quot;item&quot; determines what will be put into the opened array. It does not really matter what it is, as long as it is unique for each group (unless you want items to open and close together, then they should have the same value).

Here it is in a snippet:

<!-- begin snippet: js hide: true console: true babel: false -->

<!-- language: lang-js -->

const {
  createApp,
  ref,
  computed
} = Vue;
const {
  createVuetify
} = Vuetify
const vuetify = createVuetify()
createApp({
  setup() {
    const menuItems = ref([{
        title: &quot;Menu Item 1&quot;,
        active: false,
        subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
      },
      {
        title: &quot;Menu Item 2&quot;,
        active: true,
        subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
      },
      {
        title: &quot;Menu Item 3&quot;,
        active: false,
        subMenuItems: [&quot;Sub Menu Item 1&quot;, &quot;Sub Menu Item 2&quot;, &quot;Sub Menu Item 3&quot;]
      }
    ])
    const opened = ref([])

    return {
      opened,
      drawer: ref(true),
      menuItems,
    }
  }
}).use(vuetify).mount(&#39;#app&#39;)

<!-- language: lang-html -->

&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;https://cdn.jsdelivr.net/npm/vuetify@3.1.9/dist/vuetify.min.css&quot; /&gt;
&lt;link href=&quot;https://cdn.jsdelivr.net/npm/@mdi/font@5.x/css/materialdesignicons.min.css&quot; rel=&quot;stylesheet&quot;&gt;
&lt;div id=&quot;app&quot; class=&quot;d-flex justify-center&quot;&gt;
  &lt;v-app&gt;
    &lt;v-card&gt;
      &lt;v-layout&gt;

        &lt;v-navigation-drawer v-model=&quot;drawer&quot; temporary&gt;
          &lt;v-list density=&quot;compact&quot; :opened=&quot;opened&quot; @update:opened=&quot;opened = $event.slice(-1)&quot;&gt;
            &lt;v-list-group v-for=&quot;item in menuItems&quot; :key=&quot;item.title&quot; :value=&quot;item&quot;&gt;
              &lt;template v-slot:activator=&quot;{props, isOpen}&quot;&gt;
                    &lt;v-list-item
                        v-bind=&quot;props&quot;
                        :key=&quot;item.title&quot; 
                        :title=&quot;item.title&quot;
                    &gt;&lt;/v-list-item&gt;
                &lt;/template&gt;

              &lt;v-list-item v-for=&quot;subMenu in item.subMenuItems&quot; :key=&quot;subMenu&quot; :title=&quot;subMenu&quot;&gt;&lt;/v-list-item&gt;
            &lt;/v-list-group&gt;
          &lt;/v-list&gt;
        &lt;/v-navigation-drawer&gt;

        &lt;v-main style=&quot;height: 500px;&quot;&gt;

        &lt;/v-main&gt;
      &lt;/v-layout&gt;
    &lt;/v-card&gt;
  &lt;/v-app&gt;
&lt;/div&gt;
&lt;script src=&quot;https://unpkg.com/vue@3/dist/vue.global.prod.js&quot;&gt;&lt;/script&gt;
&lt;script src=&quot;https://cdn.jsdelivr.net/npm/vuetify@3.1.9/dist/vuetify.min.js&quot;&gt;&lt;/script&gt;

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年3月15日 18:15:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75743318.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定