問題背景:有時候一些列表會有一些跳轉的需求,比如跳到詳情頁、或者是其他相關的頁面(比如跳到用戶列表去查看用戶的相關信息)等,此時再返回列表頁,列表頁會刷新重置。目前需求就是需要改成如下情況:
問題1、列表 - 詳情頁,返回,不刷新重置;
問題2、再點其他菜單,再返回,需要刷新重置。
解決思路:
解決需求自然是想到vue的keep-alive去緩存組件,但是緩存組件有個不好的弊端,就是以后再進入頁面也一直保持着上一次瀏覽的狀態,那么如果我們有很多查詢條件的情況,或者比如 route/:id 這種動態路由匹配的情況,那么頁面就不會重新加載。
對於這個需求,組里人員意願傾向於全部緩存頁面,利用 keep-alive 的include、exclude屬性去緩存需要緩存的頁面;然后對於如果有特殊需要刷新頁面的查詢參數,比如動態路由的那種情況,就利用watch或activated去解決。個人認為這種解決方案既繁瑣,又不易維護。
所以一直再想一個通用的方案。我一直的思路就是:
1、利用路由的meta信息增加:meta: {keepAlive: true}
2、利用路由的beforeRouteLeave,如果跳出去的頁面是需要返回不刷新頁面的路由(如詳情、用戶列表),那么就給當前路由meta.keepAlive = true,否則設為false
beforRouteLeave (to, from, next) { if (['orderDetaiInfo'].includes(to.name)) { from.meta.keepAlive = true } else { from.meta.keepAlive = false } next() }
3、然后在app.vue里面去控制
<el-container class="app app_console" v-else-if="$route.fullPath != '/'">
<WHeader></WHeader>
<el-container class="forIE">
<WMenu></WMenu>
<keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> <router-view v-else :key="activeQuery"></router-view> </keep-alive>
<img class="material" src="./assets/commonImages/pattern.png" height="240">
</el-container>
</el-container>
當時想的也比較簡單,需要緩存的時候就走的keepAlive為true的view,再回來就會緩存不刷新了。當跳至其他菜單后,其keepAlive就置為false了,那么再返回時就走的下面有key值刷新的view了。
問題完成一半,測試發現一個問題:
上面問題背景的1、2是可以很好的解決了,但是卻出現第3個問題:
問題3:問題1、2之后再點擊詳情,再返回,卻不是剛剛那個頁面,而是之前緩存的頁面。
原因:問題3的此時,該頁面比如order頁的meta的keepAlive此時是false的,那我在order當前頁面進入的時候去改變為true,依然不會有效果,原因就是我們上面是形成了2個view,我們緩存的是上面那個view,就算改成true了,再返回時也是去的上面那個view,所以是返回之前緩存的頁面,很惆悵。
解決方案其實也很簡單,那么就是想法讓從其他菜單,再進入當前order時,讓進入的view變成keepAlive的就行了。
當時一直沒想到一個好的方案,就只想到利用go(0),讓頁面重進一次,這樣確實解決了問題3,但是體驗不好。一度妥協去用watch,但是今天突然想到我可以利用一個blank空的頁面去承接一下keepAlive的false的情況,相當於利用blank頁面去達到go(0),讓頁面重進的目的,但是體驗又不會刷新,由於是空頁面,所以幾乎看不出問題。
就寫下簡單方案:keep-alive,beforeRouteLeave,vuex,blank.vue
1、vuex存一個keepAlive控制什么情況進入blank頁面
什么情況呢?(1)keepAlive為false;(2)需為那些需要緩存的頁面,也就是加了meta.keepAlive為true的路由。否則沒加的那些路由也都會走進blank頁,影響結果。
<el-container class="app app_console" v-else-if="$route.fullPath != '/'">
<WHeader></WHeader>
<Blank v-if="!keepAlive && ['orderList'].includes($route.name)"></Blank>
<el-container v-else class="forIE">
<WMenu></WMenu>
<keep-alive>
<router-view v-if="$route.meta.keepAlive"></router-view>
<router-view v-else :key="activeQuery"></router-view>
</keep-alive>
<img class="material" src="./assets/commonImages/pattern.png" height="240">
</el-container>
</el-container>
2、beforeRouteLeave的時候,如果調整其他菜單項,那么就給vuex的keepAlive置為false,讓下次再進入order的時候,進入blank頁面
3、在blank頁面進行處理:(1)修改當前order頁面meta.keepAlive為true;(2)修改vuex的keepAlive為true,促使重新進入下面的緩存頁面。
這樣就大功告成了。只是自己大致測了一下,優化暫未考慮。