在構建SPA應用時,經常遇到的場景就是列表頁面 跳轉到詳情頁,但是詳情頁面回退到列表頁面,列表頁面有重新刷新了。
如何保證回退的時候不刷新頁面呢?keep-alive是一個非常好的解決方案(當然你也可以以子路由,以絕對定位形勢覆蓋上去*_*)。
keep-alive的作用
keep-alive是Vue的內置組件,能在組件切換過程中將狀態保留在內存中,防止重複渲染DOM。
本篇主要講keep-alive的用法。
keep-alive用法
像Tabs加載動態組件(有的童鞋直接用動態組件取代路由功能——個人不推薦)
緩存組件
<keep-alive> <component include="a" exclude="b"> <!-- name 爲 a 的組件將被緩存!,name 爲 b 的組件不被緩存! --> </component> </keep-alive>
緩存路由
<keep-alive include="a"> <router-view> <!-- 只有路徑匹配到的視圖 a 組件會被緩存! --> </router-view> </keep-alive>
推薦用法:不需要例舉出需要被緩存組件名稱
<keep-alive> <router-view v-if="$route.meta.keepAlive"> <!-- 這裏是會被緩存的視圖組件,比如 Home! --> </router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"> <!-- 這裏是不被緩存的視圖組件,比如 Edit! --> </router-view>
其實就是用keep-alive包括原來的組件即可,包括的組件並不像普通組件的那樣,slot。keep-alive只是一個抽象組件。具體看下篇的《vue keep-alive(2):剖析keep-alive的實現原理—學習筆記整理》。
keep-alive 的props
-
include - 字符串或正則表達,只有匹配的組件會被緩存
-
exclude - 字符串或正則表達式,任何匹配的組件都不會被緩存
-
max- 緩存組件的最大個數,超出上限使用LRU的策略置換緩存數據。
keep-alive+vue組件聲明週期+路由守衛
keep-alive的作用是在內存中緩存組件(不讓組件銷燬),等到下次再渲染的時候,還會保持其中的所有狀態。
注意:實際保存在內存中的不是渲染後的HTML的節點字符串,而是vue編譯後虛擬化的DOM對象。
目的是防止重複渲染DOM,當數據發生了變化時,纔會促發VM的diff更新。
vue所有功能的實現都是圍繞其生命週期進行的,在生命週期的不同階段調用對應的鉤子函數可以實現組件數據管理和DOM渲染兩大重要功能。
keep-alive緩存了組件,但是它也阻擋了vue 正常的生命週期流程。
vue的生命週期有:beforeCreate,created,beforeMonted,mounted,beforUpdate,update,beforDestroy,destroyed,詳情參看《vue2.x入坑總結—回顧對比angularJS/React》
當在不同頁面/組件之間切換的時候都會請求一些請求過的數據,每次請求都會導致重複渲染影響性能。這些數據可以存到緩存中——此時使用keep-alive將組建包裹起來,但這樣以上八種生命週期鉤子將失效。
取而代之的是activate和deactivated,在 2.2.0 及其更高版本中,activated 和 deactivated 將會在 樹內的所有嵌套組件中觸發。
-
activate:是在被包裹組建被激活的狀態下使用的生命週期鉤子(每次組件被調用時都會執行activated——包括第一次)。
-
第一次進入緩存路由/組件:beforeRouteEnter > beforeCreate > created > mounted > activated > ... ... > beforeRouteLeave > deactivated
-
再次進入組件時:beforeRouteEnter > activated > ... ... > beforeRouteLeave > deactivated
-
-
deactivated:在被包裹組件停止使用時調用
理論上:當在項目中引入keep-alive的時候,
-
頁面第一次進入,鉤子函數的觸發順序created -> mounted -> activated,
-
退出時觸發deactivated。
-
再次進入(前進或者後退)時,只觸發activated。如果created或mounted中處理刷新頁面,這個鉤子沒有被調用,無法刷新。
beforeRouteEnter 總會觸發
-
不使用 keep-alive 時,
beforeRouteEnter --> created --> mounted --> destroyed
-
使用 keep-alive 時,
beforeRouteEnter --> created --> mounted --> activated --> deactivated
更多的坑,推薦看
《Vue生命週期全解(vueRouter,keep-alive,生命週期)》
《Vue 爬坑之旅 -- keepAlive 與 vue-router 結合使用實現頁面緩存及記住滾動位置功能的實現及幾個需要注意的點》
keep-alive activate 在項目中應用
一般不只是點到詳情頁,然後直接返回怎麼簡單
狀態刷新
比如你在詳情頁面添加到了購物車,列表頁面需要展示購車數量等,需要結合vuex實現。
更多的是,每次進入這個頁面,必須請求後臺一些數據,就需要在activate裏面實現
有發現有個同事的實現是:頁面離開,settimeout,臆測一個時間去通知列表頁面,去進行操作。這個,嗯,能行,但是絕對不靠譜!
滾動條復位
可以通過:vue-keep-scroll-position 組件解決。但是這個組件,只有刷新路由的容器。如果是頁面裏面一個列表需要刷新呢?
在需要緩存的頁面,如列表頁面的beforeRouteLeave,存儲滾動條位置信息。其他操作原理類同。
// 離開時 beforeRouteLeave(to: any, from: any, next: any) { //let dom: HTMLElement|null = document.getElementById('list'); let dom = this.$refs.list; // 離開時,想辦法存儲滾動位置。 to.meta.scrollTop = dom.scrollTop; } // 返回時 activated() { // 激活後,更加存儲的信息,重新設置滾動條 const scrollTop = this.$route.meta.scrollTop; if (scrollTop) { this.$nextTick(() => { this.$refs.list.scrollTop = scrollTop; }); } }
這裏需要注意的是,不要通過監聽scroll事件,在列表頁面實時刷新滾動條位置信息——沒有必要的性能消耗。
keep-alive緩存頁面限制
僅當從B頁面回退到A頁面,恢復A頁面之前的緩存轉態。說個常見的案例吧
從面板頁面跳轉到編輯頁面,需要緩存面板頁面。即:從編輯頁面回退到面板頁面,面板頁面還是之前的那個騷年(進入前的樣子)。
面板頁面
export default [ { path: '/panel/:biz_id', name: 'panel', component: () => import(/* webpackChunkName: "panel-page-chunk" */'@/pages/panel/index.vue'), children: [ { path: 'list_panel/:os_id', name: 'listPanel', component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/list.vue'), props: route => ({ osId: route.params.os_id, }), meta: { keepAlive: true, }, }, { path: 'panel-info', name: 'panel-info', component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/info.vue'), }, ], }, { path: '/panel/:biz_id/chart_editor/:os_id/:chart_id?', name: 'chartEditor', component: () => import(/* webpackPrefetch: true */ /* webpackChunkName: "panel-page-chunk" */'@/pages/panel/chartEditor.vue'), meta: { keepAlive: false, }, props: route => ({ osId: route.params.os_id, }), }, ];
需要在面板頁面裏面,beforeRouteLeave 設置,from.meta.keepAlive = false;
在編輯頁面,beforeRouteLeave設置,to.meta.keepAlive = true;
這個其實是一般方案,如《緩存之keep-alive的理解和應用》,個人覺得這個方案比較好《vue組件緩存之keep-alive正確使用姿勢》,其實就是在路由的meta設置 路徑的權重。如一級頁面權重100,二級頁面1000,三級頁面1000。根據權重去做頁面緩存與 頁面切換動畫的滑動方向。
keep-alive需要注意的地方總結
-
先匹配被包含組件的 name 字段,如果 name 不可用,則匹配當前組件 components 配置中的註冊名稱。
-
不會在函數式組件中正常工作,因爲它們沒有緩存實例。
-
當匹配條件同時在 include 與 exclude 存在時,以 exclude 優先級最高(當前vue 2.4.2 version)。比如:包含於排除同時匹配到了組件A,那組件A不會被緩存。
-
包含在include中,但符合 exclude ,不會調用activated 和 deactivated。
參考文章:
vue學習---生命週期鉤子activated,deactivated https://www.cnblogs.com/mengtong/p/10966955.html
vue 頁面回退mounted函數不執行的問題及解決方法 https://www.cnblogs.com/candy-xia/p/11425357.html
深入理解vue-router之keep-alive https://www.jb51.net/article/122570.htm
官方:<keep-alive>組件緩存問題 #811 https://github.com/vuejs/vue-router/issues/811#issuecomment-353875880
轉載本站文章《vue keep-alive(1):vue router如何保證頁面回退頁面不刷新?》,
請註明出處:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue/8236.html