用vue.js做单页应用的时候,我们可能会需要类似app页面跳转的形式:前进刷新页面,后退缓存页面。我们知道可以通过keep-alive标签来缓存一个页面,如果我们直接用keep-alive套在<router-view>上会导致所有的页面都被缓存,这可能不是你想要的,因此,我们一般的写法如下:

    1. <keep-alive >
    2.     <router-view v-if="$route.meta.keep_alive"></router-view>
    3. </keep-alive>
    4. <router-view v-if="!$route.meta.keep_alive"></router-view>

    这样通过在meta中设置哪些是需要保留的,哪些是不需要保留的,即可做到缓存想要的页面。

    1. meta: {
    2. title: '转账成功',
    3. keep_alive: false,
    4. },

    不过这样设置的页面还是有问题,就是被缓存的页面会一直被缓存,无论别人是前进来到这个页面还是别人后退来到这个页面都会缓存,无法做到前进刷新,后退缓存的效果。

    在网上搜索vue.js前进刷新,后退缓存,我们会发现很多人说利用beforeRouteLeave如下配置即可:

    1. beforeRouteLeave(to,from,next){
    2.     if(to.name==='next'){//向后走keep_alive为true
    3.         from.meta.keep_alive=true;
    4.     }else{//向前走为keep_alive为false
    5.         from.meta.keep_alive=false;
    6.     }
    7.     next();
    8. }

    就是在要发生前进刷新,后退缓存的页面的里面检测页面离开的时候,如果是向后走,就保持keep_alive为true(keep_alive默认为true),这样返回的时候页面是被缓存的;如果是向前走,keep_alive为false,那么前进的时候就不会保留。看样子好像没什么问题,可仔细一想就会发现问题,为此,做了一个小demo,说明问题出在哪。

    利用beforeRouteLeave来实现前进刷新,后退缓存

    上面就是一个需要用到前进刷新,后退缓存页面的实际场景,页面结构大致如下:

    我们注意上面的B页面,因为B页面需要先跳转到C页面绑定手机号,绑定回来之后,我们要恢复B页面填写的数据,因为如果不恢复的话,用户需要再次填写B页面的数据,就不太友好了。

    上面的demo就是利用beforeRouteLeave来实现的,我们可以发现确实做到了部分的前进刷新,后退缓存:

    1.从A->B,B页面填写完内容后回退到A,再从A->B,我们发现B没有内容了,说明前进刷新可以。

    2.从A->B,B页面填写完内容后进入C,C回退到B,B的页面数据还在,说明后退缓存可以。

    不过为什么说这个是不完善的前进刷新,后退缓存呢?我们来看看下面的操作就知道了:

    从A->B,B中填写内容如下:

    然后回退到A,这个时候keep-alive变成false了,再次进入B,这个时候应该是没有内容的,我们在B填入以下内容:

    再进入C,这个时候keep-alive为true,回退有缓存,填写完之后跳转到B,我们可以发现这个时候B页面是如下样子:

    发现问题没有,就是这个时候的B缓存的页面不是我们刚从填写的lisi,而是我们第一次缓存填写的zhangsan。

    问题原因很简单,就是第二次填写B页面的时候,B页面是在离开的时候keep-alive才变成true,这个时候是不会缓存第二次填写的内容的,当C->B时,拿的其实时第一次的缓存,而不是第二次的。

    正确操作

    我们现在看看正确的前进刷新,后退缓存的demo:

    正确实现前进刷新,后退缓存    

    这里没有设置B页面的keep_alive,因为keep_alive即使变了,vue.js不会马上保存该页面,总会有一个延迟,因此,这里就将有缓存的页面keep_alive一直设置为true。和上面相反,这里关注的时前面来的路径,用beforeRouteEnter监听,如果是来自前面的,我们就将所有的数据reset,恢复成开始的样子,关键代码如下:

    1. activated: function() {
    2.     if(this.$route.meta.reset) {//需要重设
    3.         this.reset();
    4.         this.fetchData();
    5.     }
    6. },
    7. beforeRouteEnter: function(to, from, next) {
    8.     var self = this;
    9.     if(from.path=='/') { //前面的页面
    10.         if(!to.meta.isFirst) { //第一次进入
    11.             to.meta.isFirst = true;
    12.             to.meta.reset = false;
    13.         } else { //不是第一次进入
    14.             to.meta.reset = true;
    15.         }
    16.     } else {
    17.         to.meta.reset = false;
    18.     }
    19.     next();
    20. },
    21. mounted: function() {
    22.     this.fetchData();
    23. },
    24. methods: {
    25.     fetchData:function(){//初始的操作
    26. },
    27. reset:function(){
    28.     this.name='';
    29.     this.age='';
    30.     this.money='';
    31.     this.reason='';
    32.     this.fill=false;
    33. }

    流程大致如下:

    回到顶部
    我要评论

    所有评论

      相关文章