vue中強大的緩存機制之keep-alive
最近在用vue做項目,在切換頁面時發現切換回原來的頁面無法保存原來的狀態。 如A頁面需要ajax請求數據,然后切換到B頁面做某些事情,再切換回A頁面時,A頁面又再請求數據,但是作為前端,性能優化時必須要考慮的,並且,vue構建的單頁面應用,大多數情況下是不需要重新請求數據的,這時keep-alive就派上用場了。
第一部分:vue中內置的組件
在vue中,為了方便開發者更好的使用vue,減少不必要的代碼量,作者內置了一些組件,主要有:
- component組件
- transition組件
- transition-group組件
- keep-alive組件
- slot組件
(1). component組件
- props
- is 依照is的值,來決定使用哪個組件被渲染
- inline-template 布爾值
var vm = new Vue({ el: '#example', data: { currentView: 'home' }, components: { home: { /* ... */ }, posts: { /* ... */ }, archive: { /* ... */ } } })
即在components下設置多個組件。
<component v-bind:is="currentView"> <!-- 組件在 vm.currentview 變化時改變! --> </component>
也可以直接綁定在對象上:
var Home = { template: '<p>Welcome home!</p>' } var vm = new Vue({ el: '#example', data: { currentView: Home } })
(2) transition組件
- props
- name --- string,用於自動生成 CSS 過渡類名。例如:
name: 'fade'將自動拓展為.fade-enter,.fade-enter-active等。默認類名為"v"。 - appear --- boolean, 是否在初始渲染時使用過渡。默認為false。
- css --- boolean, 是否使用過渡類。默認為
true。如果設置為false,將只通過組件事件觸發注冊的 JavaScript 鈎子。 - type --- boolean, 過渡事件類型,偵聽過渡何時結束。有效值為
"transition"和"animation"。默認 Vue.js 將自動檢測出持續時間長的為過渡事件類型。 - mode --- string,控制離開/進入的過渡時間序列。有效的模式有
"out-in"和"in-out";默認同時生效。 - enter-class --- string
- leave-class --- string
- enter-active-class --- string
- leave-active-class --- string
- appear-class --- string
- appear-active-class --- string
- name --- string,用於自動生成 CSS 過渡類名。例如:
- 事件
- before-enter
- enter
- after-enter
- before-leave
- leave
- after-leave
- before-appear
- appear
- after-appear
<transition> 元素作為單個元素/組件的過渡效果。<transition> 不會渲染額外的 DOM 元素,也不會出現在檢測過的組件層級中。它只是將內容包裹在其中,簡單的運用過渡行為。
<!-- 簡單元素 --> <transition> <div v-if="ok">toggled content</div> </transition> <!-- 動態組件 --> <transition name="fade" mode="out-in" appear> <component :is="view"></component> </transition> <!-- 事件鈎子 --> <div id="transition-demo"> <transition @after-enter="transitionComplete"> <div v-show="ok">toggled content</div> </transition> </div>
new Vue({ ... methods: { transitionComplete: function (el) { // 傳入 'el' 這個 DOM 元素作為參數。 } } ... }).$mount('#transition-demo')
(3). transition-group
tag- string, 默認為spanmove-class- 覆蓋移動過渡期間應用的 CSS 類。- 除了
mode,其他特性和<transition>相同。
<transition-group> 元素作為多個元素/組件的過渡效果。<transition-group> 渲染一個真實的 DOM 元素。默認渲染 <span>,可以通過 tag 屬性配置哪個元素應該被渲染。
注意,每個 <transition-group> 的子節點必須有 獨立的key ,動畫才能正常工作
<transition-group> 支持通過 CSS transform 過渡移動。當一個子節點被更新,從屏幕上的位置發生變化,它將會獲取應用 CSS 移動類(通過 name 屬性或配置 move-class 屬性自動生成)。如果 CSS transform 屬性是“可過渡”屬性,當應用移動類時,將會使用 FLIP 技術 使元素流暢地到達動畫終點。
(4). slot
不再贅述
第二部分: keep-alive
props包括:
- include --- 字符串或正則表達式。只有匹配的組件會被緩存。
- exclude --- 字符串或正則表達式。任何匹配的組件都不會被緩存。
用法:
<keep-alive> 包裹動態組件時,會緩存不活動的組件實例,而不是銷毀它們。正如之前所說的,如果不使用keep-alive,每次切換到一個路由下的組件時,如果有請求,就會發起ajax請求,即在離開這個組件時就已經銷毀了這個組件。和 <transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現在父組件鏈中。
當組件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命周期鈎子函數將會被對應執行。主要用於保留組件狀態或避免重新渲染。
<!-- 基本 --> <keep-alive> <component :is="view"></component> </keep-alive> <!-- 多個條件判斷的子組件 --> <keep-alive> <comp-a v-if="a > 1"></comp-a> <comp-b v-else></comp-b> </keep-alive> <!-- 和 <transition> 一起使用 --> <transition> <keep-alive> <component :is="view"></component> </keep-alive> </transition>
include和exclude是vue2.1.0新增的:
<!-- 逗號分隔字符串 --> <keep-alive include="a,b"> <component :is="view"></component> </keep-alive> <!-- 正則表達式 (使用 v-bind) --> <keep-alive :include="/a|b/"> <component :is="view"></component> </keep-alive>
注意:<keep-alive> 不會在函數式組件中正常工作,因為它們沒有緩存實例。
第三部分:
<div id="app"> <keep-alive> <router-view v-if="$route.meta.keepAlive"></router-view> </keep-alive> <router-view v-if="!$route.meta.keepAlive"></router-view> </div>
只有keep-alive設置為true的才可以被緩存:
routes: [ { path: "/", redirect: "/commodity", }, { path: '/Mall', component: Mall, name: "店鋪", meta: { keepAlive: false } }, { path: '/personal-center', component: personalCenter, name: "個人中心", }, { path: "/address", component: AddressManage, name: "地址管理" }, { path: '/order', component: Myorder, name: "我的訂單" }, { path: '/commodity', component: Commodity, name: "商品",
meta: { keepAlive: true }
}, { path:"/Mall/payment", component: Ordersettlement, name: "支付信息" } ]
如下所示: 只有商品這一頁才可以被緩存,其他的都不能緩存。

在這里,無論怎么切換路由,都只有Commodity一直存在,並且顯示 inactive, 即不活躍,緩存的意思。
這時,我們可以在商品頁設置一個 activated 鈎子函數:
activated: function () { alert("activated"); },
這時,只要從別的頁面切換過來,都會alert activated,表示已經緩存了。
而其他的頁面鈎子函數 deactive 會被調用
第三部分: 遇到的坑
使用keep-alive固然是好,但是並不是所有情況下都適合使用keep-alive,因為keep-alive意味着頁面省去了重新掛載渲染,這貌似很好,但是這更意味着我們沒法使用 created updated mounted 這些生命周期鈎子函數了,所以只有在固定不變的地方我們才建議使用keep-alive, 否則不適用。
比如下面的這個頁面:

僅僅是介紹了一些店鋪的基本信息,並沒有介紹到更多的內容,所以這時我們就可以使用keep-alive了,但是,這時使用keep-alive並不是萬能的,因為一旦用戶刷新了頁面,而我們的state是在首頁獲取的,就會出現問題。
所以,更為普遍的方法是下面這樣的:
created () {this.updateMall(); }
即如果創建了新的頁面,那么一定會觸發created鈎子函數,然后我們再去請求數據,這樣就是一種很好的做法了。
