一、前言
最近在做新vue項目的時候遇到了一個問題,就是tab間的切換沒有問題,當跳轉到其他頁面時,且這個頁面並非子路由,再用瀏覽器的返回按鈕返回首頁時,tab的active始終指向默認的第一個選項。
感覺這還是個比較常見的問題,但是在網上居然沒怎么搜索到,自己摸索了一下,搞了一個解決辦法出來。由於項目的骨架部分及tab並不是我寫的,在此只根據原本的代碼給出一個解決方案。
二、代碼
1. 監聽返回
想要解決這個問題,首先要監聽到返回首頁的事件,然后把具體的路由值傳到Tabbar這個組件里。
// index.vue
<template>
<div>
<router-view></router-view>
<Tabbar :active="tabActive"></Tabbar>
</div>
</template>
<script>
import Tabbar from './../components/tabbar'
export default {
data() {
return {
tabActive: 'home/home'
}
},
components:{
Tabbar
},
beforeRouteEnter: (to, from, next) => {
next(vm => {
vm.tabActive = 'home/' + to.name;
});
},
}
</script>
這里用到了beforeRouteEnter這個路由鈎子,在vue-router的官網叫做組件內的路由導航守衛。這個鈎子可以監聽到從其他非子路由的頁面通過點擊瀏覽器的返回按鈕跳轉到首頁的事件,然后把這個路由to.name傳遞到Tabbar組件內。
2. 改變組件內狀態
// Tabbar.vue
<template>
<div class='tabbar'>
<Item txt='自選' mark='home/home' :sel='selected' @change='getVal'>
<img src='../assets/images/index1.png' slot='activeImg'/>
<img src='../assets/images/index0.png' slot='normalImg'/>
</Item>
<Item txt='詢價' mark='home/inquiry' :sel='selected' @change='getVal'>
<img src='../assets/images/inquiry1.png' slot='activeImg'/>
<img src='../assets/images/inquiry0.png' slot='normalImg'/>
</Item>
<Item txt='訂單' mark='home/hold' :sel='selected' @change='getVal'>
<img src='../assets/images/hold1.png' slot='activeImg'/>
<img src='../assets/images/hold0.png' slot='normalImg'/>
</Item>
<Item txt='賬戶' mark='home/mine' :sel='selected' @change='getVal'>
<img src='../assets/images/mine1.png' slot='activeImg'/>
<img src='../assets/images/mine0.png' slot='normalImg'/>
</Item>
</div>
</template>
<script>
import Item from './item'
export default {
props: ['active'],
components: {
Item
},
data: function(){
return {
selected: 'home/home'
}
},
watch: {
'active'(newVal,oldVal) {
this.selected = newVal;
}
},
methods: {
getVal: function(val){
this.selected = val;
}
}
}
</script>
<style>
.tabbar{width: 100%; height: 2.8rem; border-top: 1px solid #ccc; position: fixed; left: 0; bottom: 0;background-color: white;}
</style>
在Tabbar組件內首先通過props接受到外部傳進來的active值,再用watch監聽器監聽active的變化,將新值賦給selected,這樣就可以完美解決這個問題了。
最后給出其中Item組件的代碼:
<template>
<div class='itemWrap' @click='fn'>
<span v-show='bol'><slot name='activeImg'></slot><br/></span>
<span v-show='!bol'><slot name='normalImg'></slot><br/></span>
<span :class='{active: bol}'>{{ txt }}</span>
</div>
</template>
<script>
export default {
props: ['txt', 'mark', 'sel'],
computed: {
bol: function(){
if (this.mark == this.sel){
return true;
}
return false;
}
},
methods: {
fn: function(){
this.$emit('change',this.mark);
this.$router.push('/' + this.mark);
}
}
}
</script>
<style>
.itemWrap{width: 25%; float: left; text-align: center; font-size:0;}
.itemWrap img{width: 1.2rem;height: 1.2rem;margin-top: 0.5rem;}
.itemWrap span{font-size: 0.6rem; color: #666;}
.itemWrap .active{color: #dc4537;}
</style>
三、結語
感覺這個Tabbar寫得有些復雜,但是解決此問題的辦法應該是比較通用的。希望可以幫到和我遇到一樣問題的人。