Vue非同步元件處理路由元件載入狀態

fisher-zh發表於2019-03-04

問題場景

在大型單頁面應用中,處於對效能的考慮和首屏載入速度的要求,我們一般都會使用webpack的程式碼分割和vue-router的路由懶載入功能將我們的程式碼分成一個個模組,並且只在需要的時候才從伺服器載入一個模組。

但是這種解決方案也有其問題,當網路環境較差時,我們去首次訪問某個路由模組,由於載入該模組的資源需要一定的時間,那麼該段時間內,我們的應用就會處於無響應的狀態,使用者體驗極差。

解決方案

這種情況,我們一方面可以縮小路由模組程式碼的體積,靜態資源使用cdn儲存等方式縮短載入時間,另一方面則可以路由元件上使用非同步元件,顯示loading和error等狀態,使使用者能夠得到清晰明瞭的操作反饋。
Vue官方文件-動態元件&非同步元件

具體實現

  1. 宣告方法,基於Vue動態元件工廠函式來返回一個Promise物件
/**
 * 處理路由頁面切換時,非同步元件載入過渡的處理函式
 * @param  {Object} AsyncView 需要載入的元件,如 import(`@/components/home/Home.vue`)
 * @return {Object} 返回一個promise物件
 */
function lazyLoadView (AsyncView) {
  const AsyncHandler = () => ({
    // 需要載入的元件 (應該是一個 `Promise` 物件)
    component: AsyncView,
    // 非同步元件載入時使用的元件
    loading: require(`@/components/public/RouteLoading.vue`).default,
    // 載入失敗時使用的元件
    error: require(`@/components/public/RouteError.vue`).default,
    // 展示載入時元件的延時時間。預設值是 200 (毫秒)
    delay: 200,
    // 如果提供了超時時間且元件載入也超時了,
    // 則使用載入失敗時使用的元件。預設值是:`Infinity`
    timeout: 10000
  });
  return Promise.resolve({
    functional: true,
    render (h, { data, children }) {
      return h(AsyncHandler, data, children);
    }
  });
}
複製程式碼
  1. 引入路由
const helloWorld = () => lazyLoadView(import(`@/components/helloWorld`))
複製程式碼
  1. vue-router中使用
routes: [
    {
        path: `/helloWorld`,
        name: `helloWorld`,
        component: helloWorld
    }
]
複製程式碼

至此,改造已經完成,當你首次載入某一個元件的資源時(可以將網速調為 slow 3g,效果更明顯),就會顯示你在loading元件的內容,而當超出超時時間仍未載入完成該元件時,那麼將顯示error元件的內容(建議error元件儘量簡單,因為當處於低速網路或者斷網情況下時,error元件內的圖片資源等有可能出現無法載入的問題)

關於使用非同步元件後路由鉤子失效的問題

在使用本文的配置對路由引入方式進行重構後,會出現路由鉤子無法使用的問題,這個問題也是剛剛發現,在查閱資料後發現,vue-router目前對於這種使用方法是不支援的…
官方解釋為:

> WARNING: Components loaded with this strategy will **not** have access to
in-component guards, such as `beforeRouteEnter`, `beforeRouteUpdate`, and
`beforeRouteLeave`. If you need to use these, you must either use route-level
guards instead or lazy-load the component directly, without handling loading
state.
複製程式碼

連結:github.com/vuejs/vue-r…

關於使用非同步元件後路由鉤子失效的解決方法

  1. 需要使用路由鉤子的頁面放棄非同步載入,使用普通的懶載入
  2. 使用created, mounted等鉤子替代路由鉤子
    其他辦法進一步查詢中,歡迎各位在評論中提出問題和解決方案。

相關文章