vue中,咱們所要實現的一個場景就是:vue
1.搜索頁面==>到搜索結果頁時,搜索結果頁面要從新獲取數據,瀏覽器
2.搜索結果頁面==>點擊進入詳情頁==>從詳情頁返回列表頁時,要保存上次已經加載的數據和自動還原上次的瀏覽位置。緩存
最近在項目中遇到這個問題,思考了幾套方案,老是不太完善。百度搜到的方案也基本都只能知足一些很簡單的需求。對於複雜一些的狀況,仍是有些不完善的地方。如下是我的對於這種場景的一個摸索,也參考了百度。若有更好的方案,歡迎指出。bash
<keep-alive>
<router-view v-if="$route.meta.keepAlive"/>
</keep-alive>
<router-view v-if="!$route.meta.keepAlive"/>複製代碼
這裏是根據路由中的meta源信息中的keepAlive字段來判斷當前路由組件是否須要緩存。這裏的meta的keepAlive是咱們自定義的,固然你也能夠叫別的名字。app
下面在router/index.js即咱們的路由文件中,定義meta信息:函數
// list是咱們的搜索結果頁面
{
path: '/list',
name: 'List',
component: resolve => require(['@/pages/list'], resolve),
meta: {
isUseCache: false, // 這個字段的意思稍後再說
keepAlive: true // 經過此字段判斷是否須要緩存當前組件
}
},複製代碼
上面的component: resolve => require(['@/pages/list'], resolve)這裏的組件引入方式可能和你們平時寫的有些不同,這裏是爲了路由的懶加載用的,你們能夠忽略。按照正常的import引入也能夠,這個和本次的主題無關。如此一來,vue的路由會幫咱們去緩存list頁面。ui
說這以前,先簡單說一下和緩存相關的vue鉤子函數。this
設置了keepAlive緩存的組件:spa
第一次進入:beforeRouterEnter ->created->…->activated->…->deactivatedcode
後續進入時:beforeRouterEnter ->activated->deactivated
能夠看出,只有第一次進入該組件時,纔會走created鉤子,而須要緩存的組件中activated是每次都會走的鉤子函數。因此,咱們要在這個鉤子裏面去判斷,當前組件是須要使用緩存的數據仍是從新刷新獲取數據。思路有了,下面咱們來實現:
// list組價的activated鉤子
activated() {
// isUseCache爲false時才從新刷新獲取數據
// 由於對list使用keep-alive來緩存組件,因此默認是會使用緩存數據的
if(!this.$route.meta.isUseCache){
this.list = []; // 清空原有數據
this.onLoad(); // 這是咱們獲取數據的函數
}
},複製代碼
這裏的isUseCache 其實就是咱們用來判斷是否須要使用緩存數據的字段,咱們在list的路由的meta中已經默認設置爲false,因此第一次進入list時是獲取數據的。
因爲咱們只要列表到詳情頁的時候緩存列表頁的數據,因此咱們要在列表頁的beforeRouteLeave的鉤子判斷,若是前往的是詳情頁面,則緩存數據:
// 列表頁面的beforeRouteLeave鉤子函數
beforeRouteLeave (to, from, next) {
if (to.name == 'Detail') {
from.meta.isUseCache = true;
}
next();
},複製代碼
如今,detail返回list頁面。list頁面已經被緩存數據了,那麼如今若是前往search頁面後再前往list頁面時怎麼讓list頁面不使用緩存數據而是獲取新數據呢?答案就在list頁面的activated鉤子中:
// list組價的activated鉤子
activated() {
// isUseCache爲false時才從新刷新獲取數據
// 由於對list使用keep-alive來緩存組件,因此默認是會使用緩存數據的
if(!this.$route.meta.isUseCache){
this.list = []; // 清空原有數據
this.onLoad(); // 這是咱們獲取數據的函數
}
// 經過這個控制刷新
this.$route.meta.isUseCache = false;
},複製代碼
咱們加了一行this.$route.meta.isUseCache=false;也就是從detail返回list後,將list的isUseCache字段爲false,而從detail返回list前,咱們設置了list的isUseCache爲true。因此,只有從detail返回list才使用緩存數據,而其餘頁面進入list是從新刷新數據的。
至此,一個前進刷新、後退返回的功能基本完成了。
若是場景再複雜一丟丟,好比,若是這個詳情頁是個訂單詳情,那麼在訂單詳情頁可能會有刪除訂單的操做。那麼刪除訂單操做後會返回訂單列表頁,是須要列表頁從新刷新的。那麼咱們須要此時在訂單詳情頁進行是否要刷新的判斷。簡單改造一下詳情頁:
data () {
return {
isDel: false // 是否進行了刪除訂單的操做
}
},
beforeRouteLeave (to, from, next) {
if (to.name == 'List') {
// 根據是否刪除了訂單的狀態,進行判斷list是否須要使用緩存數據
to.meta.isUseCache = !this.isDel;
}
next();
},
methods: {
deleteOrder () {
// 這裏是一些刪除訂單的操做
// 將狀態變爲已刪除訂單
// 因此beforeRouteLeave鉤子中就會將list組件路由的isUseCache設置爲false
// 因此此時再返回list時,list是會從新刷新數據的
this.isDel = true;
this.$router.go(-1)
}
}複製代碼
至此,算是解決了個人vue項目中的這個前進刷新、後退緩存數據和瀏覽位置的問題。
最後再提一下,頁面滾動位置的問題。
問題1:咱們知道,在vue這種單頁應用中,若是你在a頁面滾動了一段距離後,此時前往b頁面後,b頁面也會停留在a頁面的滾動位置。這個問題的解決,咱們能夠利用router自己提供的功能來解決:
routes: [
{
path: '/detail',
name: 'Detail',
component: resolve => require(['@/pages/detail'], resolve)
}
],
scrollBehavior (to, from, savedPosition) {
if (savedPosition) {
return savedPosition
} else {
if (from.meta.keepAlive) {
from.meta.savedPosition = document.body.scrollTop;
}
return { x: 0, y: to.meta.savedPosition || 0 }
}
}複製代碼
scrollBehavior是路由提供的基礎功能,這段函數寫的是:
1.若是經過瀏覽器自帶的前進後退按鈕切換的路由,那麼會自動使用瀏覽默認的回滾上次頁面的瀏覽位置。
2.若是是經過vue路由進行的頁面切換。例如a前往b,首先判斷a是否是經過keep-alive緩存的組件,若是是,則在a路由的meta中添加一個savedPosition字段,而且值爲a的滾動位置。最後return的是頁面須要回滾的位置。如此一來,若是打開一個頁面,該頁面的組件路由中meta.savedPosition爲undefined的話,則頁面滾動到(0,0)的位置,這樣解決了問題1。那麼若是打開一個頁面,它的路由的meta.savedPosition有值的話,則滾動到上次瀏覽的位置,由於meta.savedPosition保存的就是上次瀏覽的位置。
若是以爲有幫助的話,就收藏一下吧!