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

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

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

meta: {
title: '转账成功',
keep_alive: false,
},

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

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

beforeRouteLeave(to,from,next){
    if(to.name==='next'){//向后走keep_alive为true
        from.meta.keep_alive=true;
    }else{//向前走为keep_alive为false
        from.meta.keep_alive=false;
    }
    next();
}

就是在要发生前进刷新,后退缓存的页面的里面检测页面离开的时候,如果是向后走,就保持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,恢复成开始的样子,关键代码如下:

activated: function() {
    if(this.$route.meta.reset) {//需要重设
        this.reset();
        this.fetchData();
    }
},
beforeRouteEnter: function(to, from, next) {
    var self = this;
    if(from.path=='/') { //前面的页面
        if(!to.meta.isFirst) { //第一次进入
            to.meta.isFirst = true;
            to.meta.reset = false;
        } else { //不是第一次进入
            to.meta.reset = true;
        }
    } else {
        to.meta.reset = false;
    }
    next();
},
mounted: function() {
    this.fetchData();
},
methods: {
    fetchData:function(){//初始的操作
},
reset:function(){
    this.name='';
    this.age='';
    this.money='';
    this.reason='';
    this.fill=false;
}

流程大致如下:

回到顶部
我要评论

所有评论

返回
邮箱:
绑定
取消
×

我要评论

回复:

昵称:(昵称不超过20个字)

图片:

邮箱:
绑定邮箱后,若有回复,会邮件通知。
提交
还可以输入500个字