简体   繁体   English

如何在 vue-router 中使用 Vuetify 选项卡

[英]How to use Vuetify tabs with vue-router

I have the following jsfiddle that has two Vuetify tabs.我有以下jsfiddle ,它有两个 Vuetify 选项卡。 The documentation doesn't show examples on using vue-router with them.该文档没有显示使用vue-router示例。

I found this Medium.com post on how to use Vuetify with vue-router , which has the following code:我在Medium.com上找到了关于如何将 Vuetify 与vue-router一起使用的帖子,其中包含以下代码:

<div id="app">
  <v-tabs grow light>
    <v-tabs-bar>
      <v-tabs-item href="/" router>
        <v-icon>motorcycle</v-icon>
      </v-tabs-item>
      <v-tabs-item href="/dog" router>
        <v-icon>pets</v-icon>
      </v-tabs-item>
    </v-tabs-bar>
  </v-tabs>

  <router-view />
</div>

However, the code is now outdated as the Vuetify 1.0.13 Tabs documentation doesn't specify a router prop in their api, so the embedded example in the post doesn't work.但是,代码现在已经过时,因为Vuetify 1.0.13 Tabs 文档没有在他们的 api 中指定router道具,因此帖子中的嵌入式示例不起作用。

I also found this StackOverflow answer which had the following code:我还发现了这个StackOverflow 答案,其中包含以下代码:

<v-tabs-item :to="{path:'/path/to/somewhere'}">

However, using the to prop doesn't work and it's also not listed in the Vuetify api.但是,使用to道具不起作用,并且它也未列在 Vuetify api 中。 In contrast, the v-button Vuetify component does list a to prop and utilizes vue-router , so I would expect a vue-router supported component to support the to prop.相比之下, v-button Vuetify 组件确实列出了一个to prop 并使用了vue-router ,所以我希望vue-router支持的组件支持to prop。

Digging around in the old old Vuetify 0.17 docs , the to prop is specified for v-tabs-item .旧的 Vuetify 0.17 文档中挖掘,为v-tabs-item指定了to道具。 It seems that support might have been removed in 1.0.13.似乎支持可能已在 1.0.13 中删除。

How can I use vue-router with Vuetify tabs?如何将vue-router与 Vuetify 选项卡一起使用?

Update更新

Holy wow!圣哇! I asked the Vuetify community to add documentation to their api, and it looks like they just added the to prop as well as other vue-router props to the Vuetify tabs docs .我要求 Vuetify 社区向他们的 api 添加文档,看起来他们只是将to prop 以及其他vue-router props 添加到Vuetify tabs docs Seriously, the community there is awesome.说真的,那里的社区很棒。

Original Answer原答案

The folks in the Vuetify community Discord were able to help me out. Vuetify 社区 Discord 中的人能够帮助我。 My updated jsfiddle now has the working code.我更新的jsfiddle现在有工作代码。

Essentially, v-tab is a wrapper for router-link , where I assume it uses slots to pass props to router-link , so putting the to prop on v-tab works fine.本质上, v-tabrouter-link的包装器,我假设它使用插槽将道具传递给router-link ,因此将to prop 放在v-tab效果很好。

The following code is an example of the working code:以下代码是工作代码的示例:

html html

<v-app dark>
  <v-tabs fixed-tabs>
    <v-tab to="/foo">Foo</v-tab>
    <v-tab to="/bar">Bar</v-tab>
  </v-tabs>
  <router-view></router-view>
</v-app>

js js

const Foo = {
  template: '<div>Foo component!</div>'
};

const Bar = {
  template: '<div>Bar component!</div>'
};

const routes = [
  { path: '/foo', component: Foo },
  { path: '/bar', component: Bar },
];

const router = new VueRouter({ routes });

new Vue({
  el: '#app',
  router,
});

Result结果

Foo 选项卡示例 条形标签示例

The template part:模板部分:

<div>
    <v-tabs
      class="tabs"
      centered
      grow
      height="60px"
      v-model="activeTab"
    >
      <v-tab v-for="tab in tabs" :key="tab.id" :to="tab.route" exact>
        {{ tab.name }}
      </v-tab>
    </v-tabs>
    <router-view></router-view>
</div>

And the js part:和 js 部分:

  data() {
    return {
      activeTab: `/user/${this.id}`,
      tabs: [
        { id: 1, name: "Task", route: `/user/${this.id}` },
        { id: 2, name: "Project", route: `/user/${this.id}/project` }
      ]
    };
  }

Routes:路线:

{
  path: "/user/:id",
  component: User1,
  props: true,
  children: [
    {
      path: "", //selected tab by default
      component: TaskTab
    },
    {
      path: "project",
      component: ProjectTab
    }
  ]
}

See codesanbox example 见codesanbox示例

I'm just adding some animation-related tips here & clarifying the use of v-tab-items vs v-tab-item .我只是在这里添加了一些与动画相关的技巧,并阐明了v-tab-itemsv-tab-item

If you have noticed, using the working markup as follows prevents the v-tabs tab switch animation to work:如果您已经注意到,使用如下工作标记会阻止 v-tabs 选项卡切换动画工作:

<v-tabs v-model="activeTab">
  <v-tab key="tab-1" to="/tab-url-1">tab 1</v-tab>
  <v-tab key="tab-2" to="/tab-url-2">tab 2</v-tab>
</v-tabs>
<router-view />

If you want to keep the tab switch animation, this is a way to do it.如果您想保留选项卡切换动画,这是一种方法。

<v-tabs v-model="activeTab">
  <v-tab key="tab-1" to="/tab-url-1" ripple>
    tab 1
  </v-tab>
  <v-tab key="tab-2" to="/tab-url-2" ripple>
    tab 2
  </v-tab>

  <v-tab-item id="/tab-url-1">
    <router-view v-if="activeTab === '/tab-url-1'" />
  </v-tab-item>
  <v-tab-item id="/tab-url-2">
    <router-view v-if="activeTab === '/tab-url-2'" />
  </v-tab-item>
</v-tabs>

Note that you can also use a v-for loop on your v-tab and v-tab-item tags as long as your to value is found among the id attribute of your v-tab-item s.请注意,您也可以在v-tabv-tab-item标签上使用v-for循环,只要在v-tab-itemid属性中找到to值即可。

If you need to place your tab contents in a different place than your tabs buttons, this is what v-tab-items is for.如果您需要将标签内容放置在与标签按钮不同的位置,这就是v-tab-items的用途。 You can place the v-tab-item s in a v-tab-items tag outside of the v-tabs component.您可以将v-tab-item放在v-tabs组件外部的v-tab-items标签中。 Make sure you give it a v-model="activeTab" attribute.确保给它一个v-model="activeTab"属性。

The answers of @roli-roli and @antoni are currect but lacking of a tiny detail. @roli-roli 和@antoni 的答案是正确的,但缺乏细节。 In fact, using their methods (almost equivalent) there is an issue in mobile views;事实上,使用他们的方法(几乎等价)在移动视图中存在问题; in fact, in such conditions tabs become swipeable.事实上,在这种情况下,标签变得可滑动。 The problem is that swiping won't update the route as expected, passing from Tab A with component A to Tab B with component B;问题是滑动不会按预期更新路由,从带有组件 A 的 Tab A 传递到带有组件 B 的 Tab B; instead, an animation will be fired and the activeTab will change, but the router won't update.相反,将触发动画并且activeTab将更改,但路由器不会更新。

TL;DR Swiping the v-tab-item does not update the router, and you get the same component under each tab. TL;DR 滑动v-tab-item不会更新路由器,您会在每个选项卡下获得相同的组件。

Solutions could be either disable the swipeability of v-tab-item or listening to the change event of the tab component to update the router accordingly.解决方案可以是禁用v-tab-item的可滑动性或监听tab组件的更改事件以相应地更新路由器。 I would advise this second solution (since swiping results pretty handy in some conditions) , but I thik that this would trigger twice the router update when clicking on the tab's label. 我会建议第二个解决方案(因为在某些情况下刷卡结果非常方便) ,但我认为这会在单击选项卡标签时触发两次路由器更新。

Here's a working example based on @roli-roli answer这是一个基于@roli-roli 答案的工作示例

Template模板

<template>
    <v-tabs v-model="activeTab">
        <v-tab v-for="tab in tabs" :key="tab.id" :to="tab.route">{{ tab.name }}</v-tab>

        <v-tabs-items v-model="activeTab" @change="updateRouter($event)">
            <v-tab-item v-for="tab in tabs" :key="tab.id" :to="tab.route">
                <router-view />          
            </v-tab-item>
        </v-tabs-items>
    </v-tabs>
</template>

Script脚本

export default {
    data: () => ({
        activeTab: '',
        tabs: [
            {id: '1', name: 'Tab A', route: 'component-a'},
            {id: '2', name: 'Tab B', route: 'component-b'}
        ]
    }),
    methods: {
        updateRouter(val){
            this.$router.push(val)
        }
    }
}

Router路由器

Set up as in previous answers.按照之前的答案进行设置。

//urls in some componet
<v-btn @click="goToUrl({name: 'RouteName1'})">
    .....
<v-list-item-title 
    @click="goToUrl({name: 'RouteName2'})"
>
    Some tab link text
 </v-list-item-title>
    ....


//tabs menu and content in other component
<v-tabs>
    <v-tab key="key_name1" :to="{ name: 'RouteName1'}">Some link 1</v-tab>
    <v-tab key="key_name2" :to="{ name: 'RouteName2'}">Some link 2</v-tab>

<v-tab-item key="key_name1" value="/url/for/route1">
    ....
<v-tab-item key="key_name2" value="/url/for/route2">
    ....

I just want to add a fix for double mounting of the new component when a tab is switched to.我只想在切换到选项卡时为新组件的双重安装添加修复程序。 You can see the question and answer here .您可以在此处查看问题和答案。

The TLDR is that if you use a v-for within the , you are going to run into a problem where the component you are switching to will be created, destroyed and then created again on each switch. TLDR 是,如果您在 中使用 v-for,您将遇到一个问题,即您要切换到的组件将被创建、销毁,然后在每次切换时再次创建。 If, like me, you do an ajax call on the create side of that, then you will be hitting your back end twice for every tab switch.如果像我一样,您在创建端执行 ajax 调用,那么您将在每次选项卡切换时点击后端两次。 You can wrap the with a to prevent that.你可以用 a 包裹来防止这种情况。

in the answer I go into depth about why this happens.在回答中,我深入探讨了为什么会发生这种情况。

The following code works for me以下代码对我有用

  <v-tabs fixed-tabs>
          <v-tab>Locations</v-tab>
          <v-tab>Employees</v-tab>
          <v-tab-item>Tab 1 content
            <locations-data/>
          </v-tab-item>
          <v-tab-item>Tab 2 content
            <employees-data/>
          </v-tab-item>
    </v-tabs>
   <script>
        import LocationsData from './Settings/Locations';
        import EmployeesData from './Settings/Employees';
        export default {
           components: {
            LocationsData,
            EmployeesData
          },
        }
   </script>

With animation and swipe enabled启用动画和滑动

And keep your existing query params: usefull eg if you have a :locale in your url:并保留您现有的查询参数:有用,例如,如果您的网址中有 :locale:

Template模板

<v-tabs v-model="activeTab">
   <v-tab v-for="tab in tabs" :key="tab.id" :to="tab.to">
    {{ tab.name }}
  </v-tab>
</v-tabs>

<v-tabs-items v-model="activeTab" @change="updateRouter($event)">
  <v-tab-item v-for="tab in tabs" :key="tab.id" :value="tab.to">
    <router-view />          
  </v-tab-item>
</v-tabs-items>

Script脚本

export default {
  data: () => ({
    activeTab: '',
  }),
  computed: {
    tabs() {
      return [
        { id: 1, name: 'Tab one', to: this.getTabPath('routeName1') },
        { id: 2, name: 'Tab two', to: this.getTabPath('routeName2') },
        { id: 3, name: 'Tab three', to: this.getTabPath('routeName3') },
        { id: 4, name: 'Tab four', to: this.getTabPath('routeName4') },
      ]
    },
  },
  methods: {
    getTabPath(name) {
      // Get the path without losing params. Usefull e.g. if you have a :locale in your url:
      return this.$router.resolve({ name, params: this.$route.params }).href
    },
    updateRouter(path) {
      // Gets called upon swipe.
      this.$router.push(path)
    },
  },
}

Using $router.resolve to get the path from a route object as explained here .使用$router.resolve作为解释得到的路由对象的路径在这里

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM