在前文Vue 全站缓存之 keep-alive : 动态移除缓存中,咱们实现了
在路由离开时动态移除缓存
这一功能,以此为基础,vue 全站使用缓存成为可能。javascript
本文长篇大论啰里啰嗦巴拉巴拉,请跳着读、反复读、随机读、躺着读……css
系列篇1:Vue 全站缓存之 keep-alive : 动态移除缓存html
本篇为系列篇2:Vue 全站缓存二:如何设计全站缓存前端
系列篇4:Vue 全站缓存之 vue-router-then :实现原理java
从早期粗暴得将 css、js 资源设定浏览器本地缓存,到后来小图标合并成大图节省请求资源,还有动态请求304状态判断,而后 ajax 开启 web2.0 时代, pjax 大放光彩,到现在 vue.js 等前端框架的繁荣盛世,全部的这一系列发展,我认为,提速
是一个核心驱动力。node
在 vue 里,支持 keep-alive 特性,经过 keep-alive ,再也不销毁旧组件为新组件让路,而是缓存起来以待未来复用,当复用缓存组件时,若是数据没有变化甚至能够直接原样恢复。连接web
将 router-view 放置到 keep-alive 中,便可粗暴的实现全部路由页的缓存功能。ajax
<!-- App.vue -->
<keep-alive><router-view class="transit-view"></router-view></keep-alive>
复制代码
最多见的一个场景是新建订单时选择地址
,新建订单是一个路由页面,去选择用户现有的地址又是一个路由页面,因此理所固然的,咱们但愿用户选择完地址回到订单页面的时候,订单里的其余数据好比选择的优惠券啊收件日期啊都能继续保持。vue-router
在大量相似的场景里,不断的出现数据保留和复用的需求,因此 vuex 出现了,经过第三方的一个公共组件来保存和中转数据,这是一个解决方案,并且仍是主流的解决方案哦。
然而换个角度,若是订单页在选择地址的时候被缓存了,回到订单页后直接复用前面的订单组件,其余数据都保留此时只要更新下地址数据,让全部的代码逻辑都集中在订单组件之中,这样的开发体验是否是会更直观更友好?
这是见仁见智的思路,各有想法,很差说谁好谁坏,咱们就先继续讨论缓存组件的方案吧。
若是全部的路由页都被缓存了,那么当你不想使用缓存的时候怎么办?好比又建了一个新订单,进入不一样文章的编辑组件,好比进入不一样的用户中心,缓存当然提了速,有时咱们也会不想要缓存功能,特别是一些表单场景,咱们既但愿填写一半进入下一页面时能保留填写的数据,咱们又但愿新进入的表单是一个全新的表单页。
咱们既但愿填写一半进入下一页面时能保留填写的数据,咱们又但愿新进入的表单是一个全新的表单页。
,
换句话说,回到上一个页面时使用缓存,进入下一个页面时不使用缓存
,
再换句话说,全部页面都用缓存,只在后退(回到上一页)时移除当前页缓存,这样下一次前进(进入当前页)时由于没有缓存就天然使用全新页面
,
也就是说,只要实现后退(回到上一页)时移除当前页缓存
这个功能,就能够了。
这是一种缓存复用的思路,为了实现后退(回到上一页)时移除当前页缓存
,由于想要实现动态肯定用户的前进后退行为比较麻烦,因此,咱们有个傻瓜式的方案:预测使用场景约定各路由页面的层级关系。
好比,在 routes 定义里,咱们能够这么定义各路由页:
// 仅供参考,此处缺乏路由组件定义
// router/index.js
routes: [
{ path: '/', redirect:'/yingshou', },
{ path: '/yingshou', meta:{rank:1.5,isShowFooter:true}, },
{ path: '/contract_list', meta:{rank:1.5,isShowFooter:true}, },
{ path: '/customer', meta:{rank:1.5,isShowFooter:true}, },
{ path: '/wode', meta:{rank:1.5,isShowFooter:true}, },
{ path: '/yingfu', meta:{rank:1.5,isShowFooter:true}, },
{ path: '/yingfu/pact_list', meta:{rank:2.5}, },
{ path: '/yingfu/pact_detail', meta:{rank:3.5}, },
{ path: '/yingfu/expend_view', meta:{rank:4.5}, },
{ path: '/yingfu/jizhichu', meta:{rank:5.5}, },
{ path: '/yingfu/select_pact', meta:{rank:6.5}, },
{ path: '/yingfu/jiyingfu', meta:{rank:7.5}, },
]
复制代码
核心的思路是,在定义路由时,在 meta 中定义一个 rank 字段来声明该路由的页面优先级, 好比 1.5 标识第 1 层如首页,2.5 表示第 2 层如商品列表页, 3.5标识第 3 层商品详情页,以此类推。
若是你们同在一层,也能够经过 1.4 和 1.5 这样小数位来约定前后层级。
总之,咱们指望的是,从第1层进入第2层是前进,从第3层回到第2层是后退。
使用Vue.mixin的方法拦截了路由离开事件,并在该拦截方法中实现后退时销毁页面缓存
。
// main.js
Vue.mixin({
beforeRouteLeave:function(to, from, next){
if (from && from.meta.rank && to.meta.rank && from.meta.rank>to.meta.rank)
{//此处判断是若是返回上一层,你能够根据本身的业务更改此处的判断逻辑,酌情决定是否摧毁本层缓存。
if (this.$vnode && this.$vnode.data.keepAlive)
{
if (this.$vnode.parent && this.$vnode.parent.componentInstance && this.$vnode.parent.componentInstance.cache)
{
if (this.$vnode.componentOptions)
{
var key = this.$vnode.key == null
? this.$vnode.componentOptions.Ctor.cid + (this.$vnode.componentOptions.tag ? `::${this.$vnode.componentOptions.tag}` : '')
: this.$vnode.key;
var cache = this.$vnode.parent.componentInstance.cache;
var keys = this.$vnode.parent.componentInstance.keys;
if (cache[key])
{
if (keys.length) {
var index = keys.indexOf(key);
if (index > -1) {
keys.splice(index, 1);
}
}
delete cache[key];
}
}
}
}
this.$destroy();
}
next();
},
});
复制代码
不行,这样只解决了动态移除缓存
的状况,让用户既能够进入新页面,也能够回到旧页面。前者进新页面问题不大,后者回到旧页面这件事咱还没讨论过呢。
即便是路由页面复用了缓存,也只是复用了缓存的组件和数据,在实际场景中,从列表 A 进入详情 B 再进入列表 C ,请问 列表 C 和列表 A 是同一个路由页,但他们的数据会同样吗?应该同样吗?
看起来,咱们获得了一个新结论,缓存页的数据也不可靠啊,摔,这日子快无法过了。
缓存的组件被复用时会触发 activated 事件,非缓存组件则会在建立时触发 created mounted 等一大堆事件,而同一个页面列表 A 进列表 B,由于 url 参数不一样,也会触发beforeRouteUpdate事件。连接1 连接2 连接3
看起来,咱们可以经过捕捉这些事件干点啥。
第一直觉是,咱们在捕捉到页面载入的事件后去拉取数据更新页面。仔细一想,咱们上面罗里吧嗦废了老半天劲是为了进入缓存页面再也不看那 loading 条的啊。摔,怎么又绕回来了。
这里提供一个笨办法,事件该捕捉咱仍是要捕捉,只是这是否去作拉取数据这个动做,咱能够有待商榷。
// list.vue
data(){
return {
params : null,
}
},
methods:{
pageenter:function(){
this.params = {
'uuid' : this.$route.query.uuid ,
};
},
}
复制代码
// list.vue
computed:{
paramsToString(){
return JSON.stringify(this.params);
},
},
watch:{
paramsToString:function(){
this.loadContent();
},
},
methods:{
loadContent:function(){
//此处拉取数据
//this.$http.get(....)
},
}
复制代码
//main.js
Vue.mixin({
/*初始化组件时,触发pageenter方法*/
mounted:function(){
if (this.pageenter)
{
this.pageenter();
}
},
// /*从其余组件返回激活当前组件时*/
activated:function(){
if (this.pageenter)
{
this.pageenter();
}
},
/*在同一组件中,切换路由(参数变化)时*/
beforeRouteUpdate:function(to, from, next){
if (this.pageenter)
{
this.$nextTick(()=>{
this.pageenter();
});
}
next();
},
});
复制代码
至此,全站缓存的框架算是基本搭好了
吗?
请继续阅读-系列篇3:Vue 全站缓存之 vue-router-then :先后页数据传递
原文来自阿星的博客:wanyaxing.com/blog/201807…