如何在 vue-router 中使用 Vuetify 选项卡
How to use Vuetify tabs with vue-router
我有以下 jsfiddle 有两个 Vuetify 选项卡。该文档没有显示使用 vue-router
的示例。
我发现这个 Medium.com post 关于如何将 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>
但是,代码现在已经过时了,因为 Vuetify 1.0.13 Tabs documentation 没有在他们的 api 中指定 router
道具,所以 post 中的嵌入式示例没有没用。
我还找到了这个 ,它有以下代码:
<v-tabs-item :to="{path:'/path/to/somewhere'}">
然而,使用 to
道具不起作用,它也没有在 Vuetify api 中列出。相比之下,v-button
Vuetify 组件确实列出了一个 to
道具并利用了 vue-router
,所以我希望 vue-router
支持的组件能够支持 to
道具。
在旧的 old Vuetify 0.17 docs 中挖掘,to
prop 是为 v-tabs-item
指定的。似乎在 1.0.13 中可能已删除支持。
如何将 vue-router
与 Vuetify 选项卡一起使用?
更新
天哪!我要求 Vuetify 社区向他们的 api 添加文档,看起来他们只是向 Vuetify tabs docs 添加了 to
道具以及其他 vue-router
道具。说真的,那里的社区很棒。
原答案
Vuetify 社区 Discord 中的人们能够帮助我。我更新后的 jsfiddle 现在有了工作代码。
本质上,v-tab
是 router-link
的包装器,我假设它使用插槽将道具传递给 router-link
,因此将 to
道具放在 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,
});
结果
我只是在此处添加一些与动画相关的提示并阐明 v-tab-items
与 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>
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.
If you need to place your tab contents in a different place than your tabs buttons, this is what v-tab-items
is for. You can place the v-tab-item
s in a v-tab-items
tag outside of the v-tabs
component. Make sure you give it a v-model="activeTab"
attribute.
模板部分:
<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
}
]
}
@roli-roli 和@antoni 的答案是正确的,但缺少一个微小的细节。事实上,使用他们的方法(几乎等效)在移动视图中存在问题;事实上,在这种情况下,选项卡变得可滑动。问题是滑动不会按预期更新路线,从带有组件 A 的选项卡 A 传递到带有组件 B 的选项卡 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)
}
}
}
路由器
按照之前的答案进行设置。
以下代码适合我
<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>
//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">
....
启用动画和滑动
并保留您现有的查询参数:有用的,例如如果您的 url:
中有 :locale
模板
<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>
脚本
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)
},
},
}
使用 $router.resolve
从路由对象获取路径,如 所述。
我只想添加一个修复程序,用于在切换到选项卡时双重安装新组件。
可以看到问答.
TLDR 是,如果您在 中使用 v-for,您将 运行 遇到一个问题,即您要切换到的组件将在每次切换时创建、销毁然后再次创建.如果像我一样,您在创建端执行 ajax 调用,那么您将在每次标签切换时点击后端两次。您可以用 a 包裹起来以防止出现这种情况。
在回答中我深入探讨了为什么会发生这种情况。
我有以下 jsfiddle 有两个 Vuetify 选项卡。该文档没有显示使用 vue-router
的示例。
我发现这个 Medium.com post 关于如何将 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>
但是,代码现在已经过时了,因为 Vuetify 1.0.13 Tabs documentation 没有在他们的 api 中指定 router
道具,所以 post 中的嵌入式示例没有没用。
我还找到了这个
<v-tabs-item :to="{path:'/path/to/somewhere'}">
然而,使用 to
道具不起作用,它也没有在 Vuetify api 中列出。相比之下,v-button
Vuetify 组件确实列出了一个 to
道具并利用了 vue-router
,所以我希望 vue-router
支持的组件能够支持 to
道具。
在旧的 old Vuetify 0.17 docs 中挖掘,to
prop 是为 v-tabs-item
指定的。似乎在 1.0.13 中可能已删除支持。
如何将 vue-router
与 Vuetify 选项卡一起使用?
更新
天哪!我要求 Vuetify 社区向他们的 api 添加文档,看起来他们只是向 Vuetify tabs docs 添加了 to
道具以及其他 vue-router
道具。说真的,那里的社区很棒。
原答案
Vuetify 社区 Discord 中的人们能够帮助我。我更新后的 jsfiddle 现在有了工作代码。
本质上,v-tab
是 router-link
的包装器,我假设它使用插槽将道具传递给 router-link
,因此将 to
道具放在 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,
});
结果
我只是在此处添加一些与动画相关的提示并阐明 v-tab-items
与 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>
Note that you can also use a
v-for
loop on yourv-tab
andv-tab-item
tags as long as yourto
value is found among theid
attribute of yourv-tab-item
s.If you need to place your tab contents in a different place than your tabs buttons, this is what
v-tab-items
is for. You can place thev-tab-item
s in av-tab-items
tag outside of thev-tabs
component. Make sure you give it av-model="activeTab"
attribute.
模板部分:
<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
}
]
}
@roli-roli 和@antoni 的答案是正确的,但缺少一个微小的细节。事实上,使用他们的方法(几乎等效)在移动视图中存在问题;事实上,在这种情况下,选项卡变得可滑动。问题是滑动不会按预期更新路线,从带有组件 A 的选项卡 A 传递到带有组件 B 的选项卡 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)
}
}
}
路由器
按照之前的答案进行设置。
以下代码适合我
<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>
//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">
....
启用动画和滑动
并保留您现有的查询参数:有用的,例如如果您的 url:
中有 :locale模板
<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>
脚本
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)
},
},
}
使用 $router.resolve
从路由对象获取路径,如
我只想添加一个修复程序,用于在切换到选项卡时双重安装新组件。
可以看到问答
TLDR 是,如果您在 中使用 v-for,您将 运行 遇到一个问题,即您要切换到的组件将在每次切换时创建、销毁然后再次创建.如果像我一样,您在创建端执行 ajax 调用,那么您将在每次标签切换时点击后端两次。您可以用 a 包裹起来以防止出现这种情况。
在回答中我深入探讨了为什么会发生这种情况。