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

IT技术 javascript vue.js vuejs2 vuetify.js
2021-02-26 16:29:55

我有以下jsfiddle,它有两个 Vuetify 选项卡。该文档没有显示vue-router与它们一起使用的示例

我找到了这篇关于如何使用 Vuetify 的Medium.com 帖子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>

但是,代码现在已经过时,因为Vuetify 1.0.13 Tabs 文档没有router在他们的 api 中指定prop,所以帖子中的嵌入示例不起作用。

我还发现了这个StackOverflow 答案,它有以下代码:

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

但是,使用toprop 不起作用,它也没有列在 Vuetify api 中。相比之下,v-buttonVuetify 组件确实列出了一个toprop 并使用了vue-router,所以我希望vue-router支持的组件支持该toprop。

旧的 Vuetify 0.17 文档中挖掘toprops被指定为v-tabs-item. 似乎支持可能已在 1.0.13 中删除。

如何vue-router与 Vuetify 选项卡一起使用

6个回答

更新

圣哇!我要求 Vuetify 社区向他们的 api 添加文档,看起来他们只是将toprop 以及其他vue-routerprops 添加到Vuetify tabs docs说真的,那里的社区很棒。

原答案

Vuetify 社区 Discord 中的人们能够帮助我。我更新的jsfiddle现在有工作代码。

本质上,v-tab是 的包装器router-link,我假设它使用插槽将props传递给router-link,因此将toprops放在上面v-tab效果很好。

以下代码是工作代码的示例:

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

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,
});

结果

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

问题是让动画在路线之间工作......
2021-04-29 16:29:55
如果你想将 props 传递给组件怎么办?
2021-05-13 16:29:55
谢谢你!如果有人感兴趣,我已经创建了更新的小提琴的分支,以向选项卡添加默认路由:jsfiddle.net/thorne51/9g2zeow1/2
2021-05-14 16:29:55

模板部分:

<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>

和 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` }
      ]
    };
  }

路线:

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

见codesanbox示例

我看到的问题是在尝试执行此操作时,它最终将每个页面加载两次。如果您仔细观察,mounted()您会发现它在使用选项卡进行路由时会加载页面两次。需要为此找到解决方法。Codesandbox.io/s/vuetify-v-tabs-with-vue-router-in1le用于“构建加载”的观察控制台应该只执行一次,但它实际上安装了两次。
2021-04-23 16:29:55
我想到了。注意到你正在运行的路由视图循环。您不应该在选项卡数组中运行路由视图。导致它加载两次。
2021-04-24 16:29:55
为什么需要道具?如果 props 和 router 有关系,你可以通过 router 传递 props。
2021-05-01 16:29:55
如果组件需要父级的 props 怎么办?
2021-05-05 16:29:55
@timothymarois 你是绝对正确的。我更新了我的答案,现在它应该按预期工作。
2021-05-08 16:29:55

我只是在这里添加一些与动画相关的技巧并阐明v-tab-itemsvs的使用v-tab-item

如果您已经注意到,使用如下工作标记会阻止 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 />

如果您想保留选项卡切换动画,这是一种方法。

<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>

请注意,只要s属性中找到您的,您也可以v-forv-tabv-tab-item标签使用循环toidv-tab-item

如果您需要将选项卡内容放置在与选项卡按钮不同的位置,这就是v-tab-items它的用途。您可以将v-tab-items 放在组件v-tab-items外部的标签中v-tabs确保你给它一个v-model="activeTab"属性。

@roli-roli 和@antoni 的答案是正确的,但缺少细节。事实上,使用他们的方法(几乎等价)在移动视图中存在问题;事实上,在这种情况下,标签变得可滑动。问题是滑动不会按预期更新路由,从带有组件 A 的 Tab A 传递到带有组件 B 的 Tab B;相反,将触发动画并activeTab更改,但路由器不会更新。

TL;DR 刷卡v-tab-item不会更新路由器,您会在每个选项卡下获得相同的组件。

解决方案可以是禁用可滑动性v-tab-item或侦听tab组件的更改事件以相应地更新路由器。我会建议第二种解决方案(因为在某些情况下刷卡结果非常方便),但我认为这会在单击选项卡的标签时触发两次路由器更新。

这是一个基于@roli-roli 答案的工作示例

模板

<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>

脚本

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)
        }
    }
}

路由器

按照之前的答案进行设置。

要禁用标签滑动,只需使用这样的touchless属性<v-tabs-items v-model="..." touchless>
2021-04-22 16:29:55
我看到的问题是在尝试执行此操作时,它最终将每个页面加载两次。如果您仔细观察,mounted()您会发现它在使用选项卡进行路由时会加载页面两次。需要为此找到解决方法。Codesandbox.io/s/vuetify-v-tabs-with-vue-router-in1le用于“构建加载”的观察控制台应该只执行一次,但它实际上安装了两次。
2021-04-25 16:29:55
谢谢!使用 :value="tab.route" 而不是 :to 和 <router-view>
2021-04-27 16:29:55
我想到了。注意到你正在运行的路由视图循环。您不应该在选项卡数组中运行路由视图。导致它加载两次。
2021-05-08 16:29:55
@Stevie-RayHartog 是的,我更正了那个误写的路由器视图。你为什么建议使用 :value 而不是 :to ?
2021-05-15 16:29:55
//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">
    ....