双层路由模式的tab栏嵌套
项目中有同一页面有两层tab栏,且都要采用路由模式,即url必须和TabItem相关联,例如:
-
下面是第一层tab,当前url地址为:https://…/home,“首页"要被选中;
-
这是两层tab的情况,地址栏中输入url:https://…/setting/user,不仅第一层中“设置”要被选中,第二层中“个人资料”也要选中;
-
同时,只要切换TabItem,url也要相应改变
下面是最外层tab的主要代码,用的是ant-design-vue组件库,其他组件库灵活变化同样可实现:
<template>
<a-layout>
<a-layout-sider width="15%">
<a-menu
:default-selected-keys="defaultTabItem"
@click="handleClick"
router
>
<a-menu-item v-for="item in menuList" :key="item.id">
<a-icon :type="item.path" />
<!-- <img :src="item.src" alt=""> -->
<span class="nav-text">{{ item.title }}</span>
</a-menu-item>
</a-menu>
</a-layout-sider>
<a-layout-content :style="{ margin: '0', background: '#fff' }">
<router-view></router-view>
</a-layout-content>
</a-layout>
</template>
<script>
export default {
data () {
return {
current: 'home',
menuList: [
{ id: 'home', path: 'home', title: '主页' },
{ id: 'setting', path: 'setting', title: '设置' }
],
defaultTabItem: []
}
},
watch: {
// 这里监听是为了只要url改变就更新界面,否则有时改变url后回车,或者前进后退,界面不会刷新
'$route.path': function () {
// set,强制view层更新,否则tab栏不会改变
this.$set(this.defaultTabItem, 0, this.$route.path.split('/')[1])
}
},
methods: {
handleClick (e) {
this.current = e.key;
this.$router.push('/' + e.key)
},
},
created () {
this.defaultTabItem.push(this.$route.path.split('/')[1]);
}
}
</script>
<style lang="less" scoped>
* {
margin: 0;
padding: 0;
}
.ant-layout-sider {
background: #f8f8f8;
.ant-menu {
margin: 0 0.24rem;
margin-top: 0.4rem;
background: #f8f8f8;
text-align: left;
}
// 重写被选中的menu样式
.ant-menu:not(.ant-menu-horizontal) .ant-menu-item-selected {
color: #fff;
background-color: #1f85ff;
border-radius: 0.04rem;
}
.ant-menu-item {
display: flex;
align-items: center;
margin: 0;
margin-bottom: 0.24rem !important;
height: 0.4rem;
font-size: 0.14rem;
}
}
</style>
还要注意一点,在一个页面中使用多层路由模式的tab栏,会报下面“路由重复的bug”,需要处理错误
// Eden 20-12-23 解决Avoided redundant navigation to current location: "/home"
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(err => err)
}