vue中前進重新整理、後退快取使用者瀏覽資料和瀏覽位置的實踐

愣錘發表於2019-03-04

vue中,我們所要實現的一個場景就是:

1.搜尋頁面==>到搜尋結果頁時,搜尋結果頁面要重新獲取資料,

2.搜尋結果頁面==>點選進入詳情頁==>從詳情頁返回列表頁時,要儲存上次已經載入的資料和自動還原上次的瀏覽位置。

最近在專案中遇到這個問題,思考了幾套方案,總是不太完善。百度搜到的方案也基本都只能滿足一些很簡單的需求。對於複雜一些的情況,還是有些不完善的地方。以下是個人對於這種場景的一個摸索,也參考了百度。如有更好的方案,歡迎指出。

  • 快取元件,vue2中提供了keep-alive。首先在我們的app.vue中定義keep-alive:
<keep-alive>      
    <router-view v-if="$route.meta.keepAlive"/>    
</keep-alive>    
<router-view v-if="!$route.meta.keepAlive"/>複製程式碼

這裡是根據路由中的meta源資訊中的keepAlive欄位來判斷當前路由元件是否需要快取。這裡的meta的keepAlive是我們自定義的,當然你也可以叫別的名字。

下面在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頁面。

  • 重新整理資料or快取資料的實現:

說這之前,先簡單說一下和快取相關的vue鉤子函式。

設定了keepAlive快取的元件:

       第一次進入:beforeRouterEnter ->created->…->activated->…->deactivated

       後續進入時: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儲存的就是上次瀏覽的位置。

如果覺得有幫助的話,就收藏一下吧!

相關文章