關於對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:筆者花了一天時間寫作,但仍覺不甚滿意,如果對該篇文章有不同見解或疑問的,歡迎評論或私信交流
以上。