手机上vue页面返回时如何保持原来的位置

发布时间 2023-07-26 15:38:53作者: jack0424

1,问题的提出

采用vue做手机评分页面的前端,页面显示多个评分项的分数和总分。

每个评分项有个修改按钮,按下后弹出新的页面,用户填写分数后按提交按钮,则保存数据、关闭页面、回到前一页。

此时,页面上显示的分数和总分会刷新,但是显示的页面位置未保留修改前的位置,而是回到了顶部显示。

这种情况如果页面上的分数项多的话,每次填完一项分数,就要下拉一次页面才能回到原来修改分数的位置,继续修改下面的分数,对用户来说非常不便。

那么,有没有办法返回前一页时显示的是离开前的位置呢?

2,走过的弯路

 从网上查阅资料,提供了以下思路:离开页面时记住页面位置,回到页面时将位置设置回原来的位置。

结果实践证明是不能成功。但严格来说,可以成功50%,上面前半句可行,后半句不可行。

 

以下是采用beforeRouteLeave事件记住当前位置,可以取得当前页面的垂直偏移位置:

beforeRouteLeave(to, from, next) {
    this.$alert(`滚动位置:${document.documentElement.scrollTop} || ${document.body.scrollTop}`);
    sessionStorage.setItem('scrollTop', document.documentElement.scrollTop || document.body.scrollTop);
    next();
},

 

但是,在返回页面的mounted事件中设置scrollTop,却始终是无效的。

以下是我曾经的尝试。无论是设置document.body.scrollTop,还是设置document.documentElement.scrollTop,还是设置window.pageYOffset,统统无效。

通过this.$nextTick或setTimeout延时设置也无效。

通过页面主div设置其scrollTop,也一样无效。

    mounted() {

        // let  a= sessionStorage.getItem('scrollTop');
        // // this.$alert(a+",mounted,"+document.documentElement.scrollTop);
        // // this.$alert("1");
        // document.body.scrollTop = 5000;
        // document.documentElement.scrollTop = 4000;
        // window.pageYOffset = 7000;
        //
        // let that=this;
        // this.$nextTick(()=>{
        //     setTimeout(()=> {
        //         let mainDiv = that.$refs.mainDiv;
        //         mainDiv.scrollTop = 1000;
        //         // document.body.scrollTop = 500;
        //         // document.documentElement.scrollTop = 400;
        //         // window.pageYOffset = 700;
        //         that.$message.info("$nextTick,"+document.body.scrollTop);
        //     }, 13)
        //
        // })
        // this.$message.info(a+",mounted,"+document.body.scrollTop);
    },

 

3,有效的方案

显然,不是上述方案不正确,而是上述方案不适用于vue前端。

经过查找资料,以下文章(以下简称原文)给出了可行方案:

https://blog.csdn.net/sinat_41694829/article/details/116018702

 

上述方案的思路是2点:用keepAlive缓存页面及记忆上次浏览位置,以及用activated刷新页面数据。

具体来说,包含以下3步:

第一步,修改app.vue

对于需缓存的页面,用<keep-alive>标签包裹。

<template>
    <div id="app">
        <keep-alive>
            <router-view v-if="isRouterAlive && $route.meta.keepAlive"></router-view>
        </keep-alive>
        <router-view v-if="isRouterAlive && !$route.meta.keepAlive"></router-view>
    </div>
</template>

第二步,修改router\index.js

将需要缓存的页面,在路径特性中申明keepAlive属性。

    {
        path: '/m_TargScore_Score/:openId/:months',
        name: 'm_TargScore_Score',
        component: m_TargScore_Score,
        meta: {
            keepAlive: true
        }
    },

第三步,修改缓存页面的activated事件

在该事件中刷新页面数据。

    activated() {
        this.initTargData();
    },

 

原文还提出要在Router中加上 scrollBehavior事件以及判断页面是否为第一次加载,但本人实测以上三步就够了。

4,总结

原文中指出,本方案的关键在于vue 的生命周期和路由钩子的相关知识点。

不使用 keep-alive 时
beforeRouteEnter --> created --> mounted --> destroyed


使用 keep-alive 时
beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次进入缓存的页面,只会触发beforeRouteEnter -->activated --> deactivated 。created和mounted不会再执行。

 

因此对于缓存的页面,刷新数据操作要放在activated 事件中执行。

在此感谢原文作者!