一、前言

最近在做新vue项目的时候遇到了一个问题,就是tab间的切换没有问题,当跳转到其他页面时,且这个页面并非子路由,再用浏览器的返回按钮返回首页时,tab的active始终指向默认的第一个选项。

感觉这还是个比较常见的问题,但是在网上居然没怎么搜索到,自己摸索了一下,搞了一个解决办法出来。由于项目的骨架部分及tab并不是我写的,在此只根据原本的代码给出一个解决方案。

二、代码

1. 监听返回

想要解决这个问题,首先要监听到返回首页的事件,然后把具体的路由值传到Tabbar这个组件里。


// index.vue

<template>
    <div>
        <router-view></router-view>
        <Tabbar :active=\"tabActive\"></Tabbar>
    </div>
</template>

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

这里用到了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>

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

</ >

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

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

<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写得有些复杂,但是解决此问题的办法应该是比较通用的。希望可以帮到和我遇到一样问题的人。

来源:https://segmentfault.com/a/1190000015944921

收藏 打印