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