關於對vue-router的優化(詳盡版)

這兩天總結了關於vue-router優化的幾點技法,做個筆記

在基於vue的移動端app中,通過vue-router可以便捷的進入某一路由或回退到上一路由,但是若不對vue-router做相關優化處理,則會造成以下幾個問題:

1.切換路由時,頻繁向後台發送請求

2.進入某一路由或回退到上一路由時,造成頁面卡頓,影響用戶體驗

基於這些困擾,我們從頭開始探究vue-router

問題1:切換路由時,頻繁向後台發送請求,以及解決辦法

在常規的路由配置下,我們使用App.vue作為app根組件:

app.vue有一個router-view標籤用於顯示內部組件,

而在router/index.js中,path為’/’的根路由映射了home,這代表home組件作為App.vue的子組件

因而,App.vue下的router-view代表了身為子組件的home.vue,而home組件作為App.vue的子組件(路由),本身又是除app.vue以外所有後代路由的根路由。

它們一起構成了整個APP路由系統。這是vue-router的常規描述。

萌新們往往會將所有的路由一股腦的與根路由配置在同一級,但事實證明,這是不可取的。

假設我們F12鍵,打開netWork -> XHR 時就會發現,

在home路由下,進入某個路由,然後回退到上個路由時,我們請求了2次數據,即點擊了要進入的路由時,請求了一次;回退到上個路由時,又請求了一次

而這與我們的期待是不一樣的:每當我們點擊一個新路由時,vue才向後台發送網路請求,而我們回退到某個路由時(比如本例,我們回退到home路由上),

則回退到的路由在沒有刷新事件前不要請求數據。

所以原因就在於此:

與根路由同級時,每次進入或回退某個路由,上一個已請求到的路由資源都被銷毀了,因而每當進入一個路由地址(無論是回退上一路由還是進入某一新路由),

app.vue都會重新載入一次router-view,vue都會向伺服器發起一次網路請求,造成伺服器實則沒必要的花銷。

並且隨著用戶不斷進入或者回退某個路由,耗費的花銷會越來越可觀

那麼,保持組件的狀態,便是解決的方法:

  • 解決方法一:使用vue內置組件keep-alive保持組件狀態

    使用keep-alive標籤包裹app.vue里router-view標籤,這樣就相當於包裹了包括home在內的所有路由組件:

<template>
//App.vue
  <div id="app">
    <keep-alive>
      <router-view/>
    </keep-alive>
  </div>
</template>

當我們打開f12再次嘗試進入或者回退到某個標籤時,發現只有在進入一個新路由地址時,才會發起請求, keep-alive可以快取router-view的內容,

這樣似乎已經達到了我們的期望,

但正是keep-alive的快取特性有一個致命的缺陷———— keep-alive也會快取動態路由的狀態

嘗試舉個例子來解釋這句話:

假設用戶進入了一個商品介面,但用戶對這個商品並不滿意,當用戶回退到上一級而進入了一個中意的商品介面卻發現,

跟剛剛那個介面一樣,且無論進入哪個商品介面都跟第一個商品介面一樣時,

這便會是keep-alive的弊端—-keep-alive標籤會快取動態路由的狀態,因而不會再進行數據請求,

這對動態路由來說是致命的

所以,這個方法是不可取的

  • 解決辦法二:更改router的配置

將home下所有子路由放置在home路由的children路由里,將子路由的子路由放置在子路由的children里,以此類推,即:

//router/index.js
{
    path: '/',
    name: 'Home',
    component: Home,
    // 根目錄的子路由,優化路由,防止每次回退或進入都會載入
    //home路由的子路由放置在自身的children路由下
    children: [
      {
        path : '/playListView',
        name:'PlayListView',
        component:() => import(/* webpackChunkName: "about" */ '../views/playListView.vue'),
        children:[
            //子路由的子路由放置在自己的children下,以此類推
          {
            path : ':id',//傳入id值,指明是哪一個playlist
            name:'PlayListViewInfo',
            component:() => import('../views/playListInfo.vue')
          }
        ]
      } 
    ]
  }

如果某一後代路由是動態路由,直接給該後代路由加動態路由參數,不加父路由的path

如果使用了該方法,則還需要給home下每一個後代路由添加router-view標籤,用以標識該路由是home根路由的後代路由

舉個栗子:

<template>
<!--  歌單視圖  歌單詳情頁-->
  <div class="page">
  <div>
    <m-header>
      全部歌單
    </m-header>
    <div class="play-wrapper">
      <play-list :data="playListData" @clickItem = 'gotoPlayListInfo '></play-list>
    </div>
  </div>
      <router-view/> <!-- 該路由組件上的router-view標籤標識它的子路由-->
</div>
</template>

ps: 如果點擊路由後有報錯: Navigating to current location (“/router”) is not allowed ,請點擊解決Navigating to current location (“/router”) is not allowed嘗試解決

這樣設置後,會出現點擊無法進入路由的結果。

但是如果打開f12會看到DOM中存在有該後代路由的dom,且點擊後,地址欄上已經顯示了子組件的路由,但用戶介面上依然只顯示了home組件,

也就是說當點擊了子路由以後,子路由顯示了,但父路由依舊存在於當前介面,阻礙了用戶的視圖

這與我們期待的有所不同: 點擊某個子路由,然後給用戶展現該路由的內容,但其實已經接近明朗————僅僅是頁面上有了父路由介面與子路由介面並存的現象

解決辦法:(提高後代組件的層級,使後代組件可以覆蓋父組件) 在home的所有後代路由的根div上添加一個叫page的class:

/* app的公共樣式common.js */
.page{
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background:#f3f4f9 ; /*與html背景色保持一致*/
    z-index: 9999; /*使用最高層級,覆蓋home組件的層級*/
    overflow: scroll;/*在移動端中使滾動可用*/
}

而以上操作完成後,就可以發現,點擊進入路由時,會發送一個網路請求,而回退到上一路由時,則不會發起請求,且頁面正常顯示;且就算進入了一個動態路由也可以正常顯示

這樣,就解決了切換路由時,頻繁向後台發送請求的問題。

問題2: 進入某一路由或回退到上一路由時,頁面會有生硬的進入顯示現象,影響用戶體驗

原因: 路由間的切換沒有添加過渡效果

基於問題一,我們可以使用vue的transition標籤包裹組件的router-view標籤,使用transition的name屬性來訂製過渡樣式

舉個栗子:

<template>
  <div class="page">
  <div>
    <m-header >全部歌手</m-header>
    <artist-list :data="artistsData"
      @clickItem="gotoArtistsInfo"
      class="artist"></artist-list>
  </div>
  <transition name="slide"><!--👈使用name屬性訂製組件過渡樣式-->
    <router-view/>   <!--👈使用transition包裹組件內的路由-->
  </transition>
  </div>
</template>

然後在app公共樣式里寫對應過渡樣式:

/*common.js*/
/*等待過程中的動畫*/
.slide-enter-active,.slide-leave-active{
    transition: all .3s;
}
.slide-enter,.slide-leave-to{
    transform: translate3d(100%,0,0);
}

這樣,便解決了頁面生硬卡頓問題。

ps:筆者花了一天時間寫作,但仍覺不甚滿意,如果對該篇文章有不同見解或疑問的,歡迎評論或私信交流

以上。

Tags: