Vue 结合 el-tab 标签实现页面跳转时,刷新保持当前页

2,577 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第8天,点击查看活动详情

之前我负责的页面实现了通过点击不同的 tab 标签页跳转到不同的页面(注意这里并非通过改访问 url,只是在一个打的页面中,套了两个页面,点击不同的 tab 标签激活对应的页面)。但这存在一个问题,如果我点击并不是第一次加载时,默认加载的页面,刷新后,就会自动跳回默认的页面,不会保持在本页面。

问题

如上面所述,利用 tab 标签进行页面切换代码块如下:

    <template>
        <el-tabs v-model="activePage" @tab-click="tabClick(activePage)">
            <el-tab-pane label="页面一" name="page1"></el-tab-pane>
            <el-tab-pane label="页面二" name="page2"></el-tab-pane>
        </el-tabs>
    </template>
    ...
    //展示嵌套页面
    <component v-bind:is="showSee"></component>

而我在页面初次加载时默认加载页面一:

    export default {
        name: "XXX"
        data() {
            return {
                activePage: 'page1',
                showSee: null,
            }
        }
    }

而点击事件 tabClick 逻辑如下:

    tabClick(val) {
        if (val == 'page1') {
            this.showSee = page1;
        } else if (val == 'page2') {
            this.showSee = page2;
        }
    }

此外,钩子函数 mounted 每次都会自动执行 tabClick,如下:

    mounted: function() {
        this.tabClick(this.activePage);
    }

这样写,就会导致每次刷新页面时,因为 activePage 默认设为了 page1,所以都会自动加载page1,即使你当时是在page2

解决思路

之前是没用到 url,不管加载哪个子页面,访问路径都是直接 ip + 端口,思路就是在 url 上将不同页面区分开来,每次刷新,会根据 url 中的标识加载对应子页面。至于 url 上的标识可以通过路由对象获取。

实现

需要另写一个方法,用于更新中间标识:

    updateType() {
        let type = this.route.query.type;
        if (type === '1') {
            this.activePage = 'page1';
        } else if (type === '2') {
            this.activePage = 'page2';
        }
        //然后再调用点击事件
        this.tabClick(this.activePage);
    }

同时,tab 点击事件也要改动一下,因为涉及到不同页面 type 的值不同:

    async tabClick(val) {
        let queryType;
        if (val == 'page1') {
            this.showSee = page1;
            queryType = '1';
        } else if (val == 'page2') {
            this.showSee = page2;
            queryType = '2';
        }
        await this.$router.push({
            query: {
                type: queryType || '1'
            }
        });
    }

此外,钩子函数 mounted 中也有所变化:

    mounted: function() {
        //页面一加载,首先执行一次 updateType() 方法
        //挂载时通过 this.$route.query.type 拿到 url 后 type 的值
        this.updateType();
    }

这样的话,在点击不同的 tab 标签时,url 中会带上 ...?type=1 或者 ...?type=2,根据 url 中 type 的不同,就可以保证刷新页面前,从 route 对象中取到当前是在哪个页面,刷新后仍然在该页面。

补充

这样的写法,控制台可能会报错(我遇到了)。错误信息类似 Uncaught (in promise) NavigationDuplicated {_name: 'NavigationDuplicated', name: 'NavigationDuplicated', message: 'Navigating to current location ("/?type=1") is not allowed', stack: 'Error/n'} at new NavigationDuplicated......

解决方法:在 main.js 中加上如下设置:

    import Router from 'vue-router'
    const originalPush = Router.prototype.push
    Router.prototype.push = function push(location) {
        return originalPush.call(this, location).catch(err => err)
    }

我在 main.jc 中加了这一段后,控制台就没报错了。

这个“刷新保持在当前页”问题也是困扰了我好一段时间,虽然最后也是《某度》的,但我的这个实现跟当时看的文章情况不太一样,那篇文章算是给了我解决的思路。也希望我这篇文章能够帮到你。
有错误,望指正!
我向你敬礼啊,Salute!