在前文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…