【问题标题】:v-list-group sub-groups won't open based on path defined in group propv-list-group 子组不会根据组属性中定义的路径打开
【发布时间】:2020-08-08 01:30:31
【问题描述】:

我有一个带有嵌套 v-list-groups 的导航侧边栏。 根据文档,v-list-group 的 "group" 属性将根据路由命名空间扩展组。

见: https://vuetifyjs.com/en/components/lists/

这适用于顶级 v-list-group。

如果我重新加载页面并且路由与“组”属性匹配,它就会打开。

它不适用于子组 v-list-groups。当我重新加载页面时,我可以看到子组关闭,所以我认为组道具正在工作。但是有什么东西让它马上就关闭了。

我的代码有点复杂,我不得不原谅我的变量命名。我正在呈现导航项目列表,如果它们没有定义子组,则它呈现为常规项目。如果他们有一个子组,它会呈现一个子组。这下降了两个级别。

这样我可以在一个json文件中定义整个导航栏并导入它。

<template>
    <v-list dense nav>
        <template v-for="(sidebarItem, sidebarIndex) in sidebarItems">
            <v-list-item
                v-if="arrayIsEmptyOrUndefined(sidebarItem.subGroup)"
                :key="sidebarIndex"
                :to="sidebarItem.linkTo"
                nuxt
            >
                <v-list-item-action>
                    <v-icon>{{ sidebarItem.icon }}</v-icon>
                </v-list-item-action>
                <v-list-item-content>
                    <v-list-item-title v-text="sidebarItem.title" />
                </v-list-item-content>
            </v-list-item>

            <v-list-group
                v-if="
                    (!arrayIsEmptyOrUndefined(sidebarItem.subGroup) &&
                    typeof sidebarItem.subGroup !== 'undefined')
                "
                :key="sidebarIndex"
                :prepend-icon="sidebarItem.icon"
                :group="sidebarItem.linkTo"
            >
                <template v-slot:activator>
                    <v-list-item-content>
                        <v-list-item-title>{{ sidebarItem.title }}</v-list-item-title>
                    </v-list-item-content>
                </template>

                <v-list-item
                    v-if="arrayIsEmptyOrUndefined(sidebarItem.subGroup)"
                    :key="subGroupIndex"
                    :to="sidebarItem.linkTo"
                    nuxt
                >
                    <v-list-item-action>
                        <v-icon>{{ sidebarItem.icon }}</v-icon>
                    </v-list-item-action>
                    <v-list-item-content>
                        <v-list-item-title v-text="sidebarItem.title" />
                    </v-list-item-content>
                </v-list-item>

                <template v-for="(subGroupItem, subGroupIndex) in sidebarItem.subGroup">
                    <v-list-item
                        v-if="arrayIsEmptyOrUndefined(subGroupItem.subGroup)"
                        :key="subGroupIndex"
                        :to="subGroupItem.linkTo"
                        nuxt
                    >
                        <v-list-item-action>
                            <v-icon>{{ subGroupItem.icon }}</v-icon>
                        </v-list-item-action>
                        <v-list-item-content>
                            <v-list-item-title v-text="subGroupItem.title" />
                        </v-list-item-content>
                    </v-list-item>

                    <v-list-group
                        v-if="
                            (!arrayIsEmptyOrUndefined(subGroupItem.subGroup) &&
                            typeof subGroupItem.subGroup !== 'undefined')
                        "
                        :key="subGroupIndex"
                        sub-group
                        :group="subGroupItem.linkTo"
                    >
                        <template v-slot:activator>
                            <v-list-item-content>
                                <v-list-item-title>{{ subGroupItem.title }}</v-list-item-title>
                            </v-list-item-content>
                        </template>

                        <v-list-item
                            v-for="(subGroupSubGroupItem, subGroupSubGroupIndex) in subGroupItem.subGroup"
                            :key="subGroupSubGroupIndex"
                            :to="subGroupSubGroupItem.linkTo"
                            nuxt
                            exact
                        >
                            <v-list-item-content>
                                <v-list-item-title v-text="subGroupSubGroupItem.title" />
                            </v-list-item-content>
                            <v-list-item-action>
                                <v-icon>{{ subGroupSubGroupItem.icon }}</v-icon>
                            </v-list-item-action>
                        </v-list-item>
                    </v-list-group>
                </template>
            </v-list-group>
        </template>
    </v-list>
</template>

如果路由命名空间同时匹配组和子组,则仅打开组。 vuetify 文档站点对此有一个有效的实现。如果你去那里并向下导航到一个子组并刷新页面。子组将打开。

【问题讨论】:

    标签: javascript vue.js vuetify.js


    【解决方案1】:

    哇!这最终比我最初预期的要困难得多。我通过直接查看source code for the Vuetify docs website,特别是main nav drawer component、base-group component、base-subgroup component 和base-item component 解决了这个问题。为了便于组合和维护,这些组件被分离到单独的文件中,但我在下面的模板中重新组合了它们:

    <template>
      <v-navigation-drawer permanent>
        <v-toolbar color="indigo" dark>
          <v-app-bar-nav-icon></v-app-bar-nav-icon>  
          <v-toolbar-title>Main Menu</v-toolbar-title>
          <v-spacer></v-spacer>
          <v-btn icon>
            <v-icon>mdi-dots-vertical</v-icon>
          </v-btn>
        </v-toolbar>
        <v-list
          dense
          expand
          nav
        >
          <!-- ENTIRE list is wrapped in a template -->
          <template v-for="item in $router.options.routes">
            <!-- use v-if to determine if 2nd level nesting is needed -->
            <!-- if it's a menu item with no children -->
            <v-list-item
              v-if="!item.children"
              color="indigo"
              :key="item.name`"
              :to="item.path"
            >
              <v-list-item-icon>
                <v-icon>{{ `mdi-${item.meta.icon}` }}</v-icon>
              </v-list-item-icon>
              <v-list-item-title>{{ item.name }}</v-list-item-title>
            </v-list-item>
            <!-- else if it has children -->
            <v-list-group
              v-else
              :group="item.path"
              color="indigo"
            >
              <!-- this template is for the title of top-level items with children -->
              <template #activator>
                <v-list-item-content>
                  <v-list-item-title>
                    <v-icon>{{ `mdi-${item.meta.icon}` }}</v-icon>
                    {{ item.name }}
                  </v-list-item-title>
                </v-list-item-content>
              </template>
              <!-- this template is for the children/sub-items (2nd level) -->
              <template v-for="subItem in item.children">
                <!-- another v-if to determine if there's a 3rd level -->
                <!-- if there is NOT a 3rd level -->
                <v-list-item
                  v-if="!subItem.children"
                  class="ml-5"
                  :key="subItem.name"
                  :to="item.path + subItem.path"
                >
                  <v-list-item-icon class="mr-4">
                    <v-icon v-text="`mdi-${subItem.meta.icon}`" />
                  </v-list-item-icon>
                  <v-list-item-title class="ml-0">
                    {{ subItem.name }}
                  </v-list-item-title>
                </v-list-item>
                <!-- if there is a 3rd level -->
                <v-list-group
                  v-else
                  color="indigo"
                  :group="subItem.path"
                  sub-group
                >
                  <template #activator>
                    <v-list-item-content>
                      <v-list-item-title>
                        <v-icon>{{ `mdi-${subItem.meta.icon}` }}</v-icon>
                        {{ subItem.name }}
                      </v-list-item-title>
                    </v-list-item-content>
                  </template>
                  <template v-for="(subSubItem, k) in subItem.children">
                    <v-list-item
                      :key="`subheader-${k}`"
                      color="indigo"
                      :value="true"
                      :to="item.path + subItem.path + subSubItem.path"
                    >
                      <v-list-item-title>{{ subSubItem.name }}</v-list-item-title>
                      <v-list-item-icon>
                        <v-icon>{{ `mdi-${subSubItem.meta.icon}` }}</v-icon>
                      </v-list-item-icon>
                    </v-list-item>
                  </template>
                </v-list-group>
              </template>
            </v-list-group>
          </template>
        </v-list>
      </v-navigation-drawer>
    </template>
    

    您可能已经注意到,菜单是从 Vue Router 中的路由列表生成的。路由器定义如下所示(注意:由于这只是一个示例,我没有将组件与每个路由关联,但实际上,这是必要的):

    const router = new VueRouter({
      routes: [
        {
          name: 'No Children (1 level)',
          path: '/no-children',
          meta: {
            icon: 'baby-carriage-off',
          },
        },
        {
          name: 'Attractions (2 levels)',
          path: '/attractions',
          meta: {
            icon: 'airballoon',
          },
          children: [
            {
              name: 'Carnivals',
              path: '/carnivals',
              meta: {
                icon: 'drama-masks',
              },
            },
            {
              name: 'Museums',
              path: '/museums',
              meta: {
                icon: 'bank',
              },
            },
          ]
        },
        {
          name: 'Restaurants (3 levels)',
          path: '/restaurants',
          meta: {
            icon: 'silverware-fork-knife',
          },
          children: [
            {
              name: 'Japanese',
              path: '/japanese',
              meta: {
                icon: 'map-marker-radius-outline',
              },
              children: [
                {
                  name: 'Hikari Sushi',
                  path: '/hikari-sushi',
                  meta: {
                    icon: 'food-croissant',
                  },
                },
                {
                  name: 'Late Night Ramen',
                  path: '/late-night-ramen',
                  meta: {
                    icon: 'noodles',
                  },
                },
              ]
            },
            {
              name: 'Italian',
              path: '/italian',
              meta: {
                icon: 'map',
              },
              children: [
                {
                  name: 'Jersey Pizza',
                  path: '/jersey-pizza',
                  meta: {
                    icon: 'pizza',
                  },
                },
                {
                  name: 'Im-pasta-ble',
                  path: '/im-pasta-ble',
                  meta: {
                    icon: 'pasta',
                  },
                },
              ]
            },
            {
              name: 'Mexican',
              path: '/mexican',
              meta: {
                icon: 'map-marker',
              },
              children: [
                {
                  name: 'Taco Gato',
                  path: '/taco-gato',
                  meta: {
                    icon: 'taco',
                  },
                },
                {
                  name: 'A-maize-ing',
                  path: '/a-maize-ing',
                  meta: {
                    icon: 'corn',
                  },
                },
              ]
            },
          ]
        },
      ]
    })
    

    Here's a full, working example on codepen。我将其配置为具有/restaurants/japanese/late-night-ramen 的起始路由,当您单击任何端点时,应用程序将被路由到的路径会记录在控制台中。希望这会有所帮助!

    【讨论】:

    • 非常好的实现!比我的干净很多,我会从你那里得到一些灵感,可以清理我的导航栏。我实现了你的实现的一个版本,它现在可以工作了!太感谢了!我认为我的代码中的一个问题是我的 v-list 没有将“expand”属性设置为 true。
    猜你喜欢
    • 2019-11-11
    • 2020-05-08
    • 2022-01-05
    • 2020-09-15
    • 2020-11-22
    • 2018-05-24
    • 2018-12-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多