Nuxt.js 踩坑筆記 - 緩存向


零、前言

  最近參與了一個立足 seo 的移動端項目,公司前端工程主棧 vue,所以理所當然的用上了 nuxt,UI 主要選擇了 Vant。
 

一、公共列表頁的緩存

  公共列表頁由於數據量較大,故需要滾動觸發分次加載以模擬分頁,當客戶端加載到了一定頁數之后(>= 2),點擊某條數據進去查看詳情,然后返回列表頁,這時候如果沒有緩存的話,列表頁會按照初始參數(即從分頁 1 開始)發請求拉數據,並且丟失瀏覽位置。一方面,浪費請求資源,另一方面,用戶體驗不佳。因此,針對這兩個問題,最后決定開啟緩存。

  vue 中的緩存直接使用 <keep-live> 組件即可,配合上 vue-router 中的 scrollBehavior 往往能比較容易地實現。當然這里容易有忽略:“scrollBehavior 只在支持 history.pushState 的瀏覽器中可用。” 接受三個參數,to, from, savedPosition, 而 savedPosition “當且僅當 popstate 導航 (通過瀏覽器的 前進/后退 按鈕觸發) 時才可用。” 這意味這個參數着只有 this.$router.go(...) 有效,this.$router.push() 時是無效的!並且,我們在使用 <keep-live> 時,通常會在自定義的路由中添加某些字段,但 nuxt 的路由是自動生成的,這里是最大的限制。

  這里有一個前置,在 nuxt.js 的 1.x 某個更新中, <nuxt> 和 <nuxtChild> 組件添加了 keepAlive 屬性。於是我們可以在 default.vue 中定制這個屬性:
<nuxt :keep-alive='viewCache' :keepAliveProps="{include: includeArr}"/>

data() {
  return {
    cache: false,
    includeArr: ['list-name-1', 'list-name-2'] // 組件的 name
  }
}

watch: {
  '$route': function(new, old) {
    if (...) {
      this.cache = true;
    } else {
      this.cache = false;
    }
  }
}

 

然后,在跳轉進入列表頁的組件上綁定相應的參數,從而控制是否需要緩存,如:
this.$router.push({
  name: 'list-name-1',
  params: {
    cache: true
  }
})

 

最后,綁定 keepAliveProps 是為了避免多余組件的緩存.
另外,從列表頁跳轉詳情頁的時候,也需要加上控制字段,如:
this.$router.push({
  name: 'details-name-1',
  params: {
    details_id: xxxxx,
    cache: true
  }
})

 

並且,從詳情頁返回時,也需要加上控制字段,如
this.$router.push({
  name: 'list-name-1',
  params: {
    cache: true
  }
})

 

  至此,可以解決請求浪費,列表數據緩存的問題,同時,缺點也比較明顯,需要在父組件/列表頁/詳情頁同時添加控制字段才能實現,耦合度較高,並且,用戶在列表頁刷新一下即失效。

  其次,對於滾動條位置記錄,在多番嘗試之后,也沒有一個較便捷的方法。原因除上文中提到的 savedPosition 的限制以外,與列表數據的緩存也有關系:整個頁面的高度需要由數據撐開,然后才能進行滾動。下面是我的解決方案,依賴上文中的組件(數據)緩存:
  
  由於列表頁不進行 ssr, 故在使用 keepAlive 時同時可以使用 vue 的 activated/deactivated 這兩個生命周期:
activated() {
  setTimeout(() => {
    window.scrollTo(0, this.scrollPosition);
    // window.scrollTo({
    //   top: this.scrollPosition,
    //   behavior: "smooth" 
    // });
  }, 0)
},
deactivated(){
  this.scrollPosition = window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
}
 
  這里需要注意的是要使用 setTimeout (或者this.$nextTick(),不過我嘗試的時候沒有效果),否則不會滾動。
  當然,這里也存在一定的問題, window.scrollTo(x, y) 動作是瞬間完成的,因此可能會存在一定的閃爍情況,而使用 window.scrollTo({..., behavior: "smooth" }) 則在每次用戶返回的時候都會有個明顯的下滑動作,所以,如何取舍,應當依據實際情況。
 
附上對列表數據緩存的實踐和資料:
* (未嘗試) 使用服務器緩存 - https://juejin.im/post/5b2b62096fb9a00e61494b0b
* ✗ 使用 van-popup/dialog 組件 - 但是會引起 asyncData 中的傳值收值
* ✗ this.$router.go 函數 - 無法緩存
* ✗ 使用 $store + van-popup/dialog,_details 是頁面級組件,如果使用 import 導入將不會觸發 asyncData 方法,從而導致某些依賴性數據為 undefinded, 最終在 rendering 過程報錯。
 

二、動態路由

  同一個文件夾下不應該存在兩個及以上的 _xxx.vue (動態)組件。
 

三、生命周期

 

  nuxt.js 的服務端渲染過程基於 node,所以其某些周期是運行在服務端的,在引入第三方插件,或者直接在代碼中使用 window 和 document 時,控制台會給出警告:window 未定義。

  解決辦法有兩種:

    1、使用 process.browser 來區分環境,如:

if (process.browser) {
  // 修改window對象下某一屬性
  window.mbk =  ...
}

    2、在 mounted 以及之后的周期中使用;

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM