vue如何使用router.meta.keepAlive對頁面進行緩存
使用router.meta.keepAlive對頁面進行緩存
需求:
1. 從stockList頁面到stockInfo頁面,從stockInfo頁面返回stockList,緩存stockList頁面
2. 從其他頁面進入到stockList頁面,則不緩存stockList頁面
路由配置文件中:
{ path: '/stockSelectionAndDiagnosticStocks', name: 'stockSelectionAndDiagnosticStocks', component: stockSelectionAndDiagnosticStocks, redirect: '/stockSelectionAndDiagnosticStocks/stockList', children: [ { path: '/stockSelectionAndDiagnosticStocks/stockList', name: 'stockList', component: stockList, // 此處設(shè)置的原因:保證第一次從stockList進入到stockInfo中是緩存了的 meta: { keepAlive: true } }, { path: '/stockSelectionAndDiagnosticStocks/stockInfo', name: 'stockInfo', component: stockInfo } ] }
App.vue中:
<div id="app"> <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> </div>
stockList.vue中:
beforeRouteLeave (to, from, next) { // 從列表頁去到別的頁面,如果不是詳情頁,則不緩存列表頁 if (to.name !== 'stockInfo') { this.$route.meta.keepAlive = false } else { this.$route.meta.keepAlive = true } next() }
*** 增加需求:從stockInfo頁面通過“特殊的”點擊事件回到stockList,stockList頁面的列表需要按照字段更新 *** stockInfo.vue中:(其中setStore、getStore是封裝的sessionStorage)
clickHistoryItem (val) { setStore('searchName', val) this.$router.push({ name: 'stockList' }) }
stockList.vue中:
// 只有當(dāng)緩存的情況寫才觸發(fā)這兩個鉤子函數(shù) activated () { if (getStore('searchName')) { this.pageIndex = 1 this.searchStockFirstStep(getStore('searchName')) } }, deactivated () { removeStore('searchName') }
使用keepAlive緩存頁面及記憶上次瀏覽位置,并刷新頁面
平時業(yè)務(wù)開發(fā)中,列表頁面是很常見的,而列表頁面有一個很常見的需求就是要緩存整個頁面,而且還要記住列表的滾動位置,當(dāng)點擊某個列表項進入詳情頁,再返回到列表頁面的時候,要能夠回到原來的滾動位置。
上面的需求我相信業(yè)務(wù)開發(fā)人員基本都碰到過,那么在 vue 中,這個需求要怎么實現(xiàn)呢,這票文章就來說一下,在實現(xiàn)這個功能的過程中,還有幾個需要注意的點后面也會說到。
一、用keep-alive實現(xiàn)路由緩存
在 vue 項目中,要想實現(xiàn)緩存功能,有一個很簡單方便的方法就是使用 keep-alive 組件,keep-alive 可以實現(xiàn)組件或路由級的緩存,這里就以路由緩存為例來說下。
1,在 App.vue 中的路由組件 router-view 上加上 keep-alive
像頁面緩存這種功能,在一個應(yīng)用中可能會有的頁面不需要,而有的頁面又需要,所以就需要將這功能放在全局,并做成可配置的,這樣才能進行靈活配置。
而整個項目的所有頁面其實都是掛在 app 這個節(jié)點下,通過 router-view 加載和顯示出來的。所以我們在 app.vue 這個文件這里給 router-view 加上 keep-alive。
? ? <!--緩存想要緩存的頁面,實現(xiàn)后退不刷新--> ? ? <!--加上v-if的判斷,可以自定義想要緩存的組件,自定義在router里面--> ? ? ? <keep-alive> ? ? ? ? <router-view v-if="$route.meta.keepAlive"></router-view> ? ? ? </keep-alive> ? ? ? <router-view v-if="!$route.meta.keepAlive"></router-view> ? </div>
- 注意點一:用 keep-alive 包裹需要緩存的路由,但是判斷條件不要寫在 keep-alive 上,需要寫在 router-view 上,不然會沒有作用
- 注意點二:當(dāng) router-view 有 transition 過渡動畫時的寫法。
如果需要自定義路由的切換過渡動畫,那么就需要在 router-view 上加上 transition 組件,當(dāng)加上 transition 之后,HTML 層級就達到了三級,然后 transition ,keep-alive ,router-view ,v-if 這幾者之間可以有多種不同的組合,在嘗試了各種不同的組合之后,我發(fā)現(xiàn)只有一種寫法可以達到緩存效果,但也有一點小瑕疵,那就是緩存的頁面不會觸發(fā)過渡動畫,這也是一個比較遺憾的地方。代碼如下:
<div id="app" class="main-app"> ? ? <!--緩存想要緩存的頁面,實現(xiàn)后退不刷新--> ? ? <!--加上v-if的判斷,可以自定義想要緩存的組件,自定義在router里面--> ? ? <!--keepAlive 的路由不會觸發(fā) transition,參見 ?? ??? ??? ??? ??? ? ? https://github.com/vuejs/vue-router/issues/811 --> ? ? <transition name='fade' mode="out-in"> ? ? ? <keep-alive> ? ? ? ? <router-view v-if="$route.meta.keepAlive"></router-view> ? ? ? </keep-alive> ? ? </transition> ? ? <transition name='fade' mode="out-in"> ? ? ? <router-view v-if="!$route.meta.keepAlive"></router-view> ? ? </transition> ? </div>
2,在 router.js 中為需要緩存的路由設(shè)置緩存參數(shù)
在上面的代碼中,有一個判斷條件 $route.meta.keepAlive ,這個條件就是用來區(qū)分該路由是否需要緩存的,這個條件需要寫在 router.js 路由表文件中。
{path: ‘/msg', name: ‘Message', meta: {keepAlive: true}, component: Message},
如上,就是在需要緩存的路由里面,給該路由加上 meta 元信息,在里面設(shè)置是否需要緩存即可。
二、記錄頁面滾動位置
要記住滾動位置,有多種實現(xiàn)方式,然而最簡單,最便捷的方式就是在路由表中加上 scrollBehavior,這也是官方推薦的方式。
new Router({ ? ? mode: 'history', ? ? scrollBehavior (to, from, savedPosition) { ? ? ? if (savedPosition) { //如果savedPosition存在,滾動條會自動跳到記錄的值的地方 ? ? ? ? return savedPosition ? ? ? } else { ? ? ? ? return {x: 0, y: 0}//savedPosition也是一個記錄x軸和y軸位置的對象 ? ? ? } ? ? }, ? ? routes: [] ?})
只要在 router.js 中加入如上的 scrollBehavior 那段代碼,就可以實現(xiàn) router-view 的記錄滾動位置的功能了,這功能是 vue 內(nèi)封裝的,用起來簡單方便。
做完上面兩步就可以實現(xiàn)簡單的頁面緩存和記住滾動位置的功能了,但是真正用起來卻發(fā)現(xiàn)僅僅是這樣還是不夠的。按照上面的代碼緩存功能是實現(xiàn)了,但是你會發(fā)現(xiàn),被緩存的頁面不會再重新請求數(shù)據(jù)了(沒有做下拉刷新等操作的時候),這樣其實是不太好的,其實我們大多數(shù)時候需要的是從列表詳情頁回到列表的時候不刷新,但是從其他頁面進入列表頁的時候需要重新請求數(shù)據(jù)。那么要怎么實現(xiàn)這么個功能呢?
三、詳情頁返回列表頁不刷新,其他頁面進入列表頁刷新
在前面的代碼中,我們實現(xiàn)了路由級的頁面緩存,也記住了頁面滾動位置,但同時也發(fā)現(xiàn)被緩存的頁面不會再重新請求數(shù)據(jù),這樣也是不行的,我們現(xiàn)在就來解決這個問題。
要解決這個問題,首先需要用到 vue 的生命周期和路由鉤子的相關(guān)知識點。因為我們這里使用了 keep-alive 組件來做緩存,所以生命周期等鉤子函數(shù)的執(zhí)行順序就有了兩種情況。
不使用 keep-alive 時
beforeRouteEnter --> created --> mounted --> destroyed
使用 keep-alive 時
beforeRouteEnter --> created --> mounted --> activated --> deactivated
再次進入緩存的頁面,只會觸發(fā)beforeRouteEnter -->activated --> deactivated 。created和mounted不會再執(zhí)行。
基于上面的兩點,我們就可以解決被緩存的頁面一直不刷新的問題了。
1,在路由的 mate 中添加一個變量,表示是否需要刷新
{path: ‘/msg', name: ‘Message', meta: {keepAlive: true, isNeedRefresh: true}, component: Message},
2,在頁面組件的 data 中定義一個變量,表示是否是第一次進入該頁面
data () { ? ? ? return { ? ? ? ? isFirstEnter: false, ? ? ? } ? ? },
3,在相關(guān)的鉤子函數(shù)中判斷是否是第一次進入頁面,是否需要重新加載數(shù)據(jù)
beforeRouteEnter (to, from, next) { ? ? ? // 利用路由元信息中的 meta 字段設(shè)置變量,方便在各個位置獲取。這就是為什么在 meta 中定義 isNeedRefresh。 ? ? ? // 當(dāng)從詳情頁返回時,將 isNeedRefresh 設(shè)為 false,表示不刷新數(shù)據(jù) ? ? ? if (from.name === 'MsgDetail') { ? ? ? ? to.meta.isNeedRefresh = false ? ? ? } ? ? ? next() ? ? }, ? ? mounted () { ? ? ? // 只有第一次進入或者刷新頁面后才會執(zhí)行此鉤子函數(shù),使用keep-alive后(2+次)進入不會再執(zhí)行此鉤子函數(shù) ? ? ? // isFirstEnter 用來標(biāo)記是否第一次進入該頁面,以防止用戶在詳情頁手動刷新頁面,回到該頁面后不再請求數(shù)據(jù) ? ? ? this.isFirstEnter = true ? ? }, ? ? activated () { ? ? ? if (this.$route.meta.isNeedRefresh || this.isFirstEnter) { ? ? ? ? // 如果 isNeedRefresh 是 true,表明需要獲取新數(shù)據(jù),否則就不再請求,直接使用緩存的數(shù)據(jù) ? ? ? ? this.queryListData() ? ? ? } ? ? ? // 恢復(fù)成默認的 false,避免 isFirstEnter 一直是 true,導(dǎo)致重復(fù)獲取數(shù)據(jù) ? ? ? this.isFirstEnter = false ? ? ? // 恢復(fù)成默認的 true,避免 isNeedRefresh 一直是 false,導(dǎo)致下次無法獲取數(shù)據(jù) ? ? ? this.$route.meta.isNeedRefresh = true ? ? },
這里面的判斷邏輯有點小繞,需要好好理解下。
完成上面的代碼也就可以實現(xiàn)從詳情頁返回不刷新,自動滾動到原先的位置,而從其他頁面進入則重新獲取數(shù)據(jù)的需求。
四、返回記錄位置的頁面需要進行刷新數(shù)據(jù)
凡是被keep-alive包裹住的頁面都會被緩存,如果想刷新內(nèi)容要啟用activated函數(shù),用法同created,activated只有在被keep-alive包裹時會觸發(fā),activated函數(shù)一進入頁面就觸發(fā)
activated(){ ? ? //返回頁面時刷新數(shù)據(jù),需要重新請求的寫在這里 ? ? this.getParkList(); ? },
五、額外需要注意的地方(沒測)
1,keep-alive 與 lazyload 同時使用時要注意
這個問題是我偶爾發(fā)現(xiàn)的,有時候會發(fā)現(xiàn)使用了 lazyload 加載的圖片有時會顯示不正確,刷新下就又正常了。這其實是 lazyload 導(dǎo)致的問題,當(dāng)單獨操作一二個數(shù)據(jù)添加或刪除的時候,lazyload 會導(dǎo)致圖片的顯示位置錯亂,我還沒找到很好的處理辦法,只有先暫時去掉 lazyload。如果有更好的處理方式,煩請告知。
2,要注意頁面布局,不要限制頁面滾動位置
在使用了 keep-alive 做路由級緩存的頁面,不要限定頁面的滾動位置,讓頁面能夠自然滾動就行,不要給滾動區(qū)域設(shè)置固定高度。設(shè)置了固定高度的話,記錄滾動位置的功能就會不起作用,緩存功能是還在,但是并不會自動記住滾動位置。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Jenkins?Sidebar?Link插件實現(xiàn)添加側(cè)邊欄功能詳解
這篇文章主要介紹了vue框架實現(xiàn)添加側(cè)邊欄,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2022-12-12Vue之beforeEach非登錄不能訪問的實現(xiàn)(代碼親測)
這篇文章主要介紹了Vue之beforeEach非登錄不能訪問的實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2019-07-07