<keep-alive>
的作用是緩存一個元件的資料狀態,即使它被切換掉,不再呈現在畫面上時,它的資料狀態依然會把存起來,並不會像一般元件那樣被銷毀。
另外,is
屬性的作用是動態載入元件,實現切換元件的效果。最常見的用法是在<component />
透過 v-bind
使用is
屬性來切換顯示元件:<component :is="...">
。而 is
屬性也可以用在 HTML 標籤上。
以下會再作詳細解說。
keep-alive
?常用情景包括:
<keep-alive>
<component />
</keep-alive>
keep-alive 是一個抽象元件,即是它不會被渲染成 DOM 節點掛載在畫面上。而被 <keep-alive>
所包著的元件的資料狀態會被緩存起來。
該元件在只會跑一次生命週期,之後只會跑 activated
和 deactivated
這兩個生命週期,代替 mounted
和unmounted
。我們可以在元件裏使用此兩個 lifecycle hook:
activated() {
...
}
deactivated() {
...
}
<keep-alive>
接收 3 個 props,讓我們更客製化指定要緩存什麼元件。
<keep-alive include="" exclude="" max="">
</keep-alive>
官方文件清楚說明每個 prop 的型別和作用:
詳細語法就不在此說明,有需要可再查看官方文件。
謹記:如果使用 include 和 exclude props 來指定元件名稱時,該元件需要有 name 屬性才會生效。
使用 include 指定元件 a 需要被緩存:
<keep-alive>
<component include="a" />
</keep-alive>
該元件要有 name 屬性:
export default {
name: 'a'
}
同樣地, router-view
也是一個元件,一樣可以被 keep-alive
包起來,把此 router-view 裏的所有元件都緩存起來:
<router-view v-slot="{ Component }">
<keep-alive>
<component :is="Component" />
</keep-alive>
</router-view>
目前 Vue 已經不容許
<router-view>
直接寫在<keep-alive>
或<transition>
裏面,需要使用v-slot
。
如果只是要緩存指定的元件,做法有兩種:
include
、exclude
。meta
屬性,再在裏面自定義屬性,讓我們在 router-view
做判斷哪些元件要被緩存。Example.vue
export default {
name: 'example'
}
App.vue
<router-view v-slot="{ Component }">
<keep-alive include="example">
<component :is="Component" />
// 只有 Example 元件會被緩存
</keep-alive>
</router-view>
router/index.js
export default [
{
path: '/example',
component: Example,
meta: {
keepAlive: true
}
}
]
App.vue
<router-view v-if="!$route.meta?.keepAlive" />
<router-view v-slot="{ Component }">
<keep-alive>
<component v-if="$route.meta?.keepAlive" :is="Component" />
</keep-alive>
</router-view>
注意,目前 Vue 已經不容許 <router-view>
直接寫在 <keep-alive>
或 <transition>
裏面,因此以下寫法會跳錯:
<template>
<router-view v-if="!$route.meta.keepAlive" />
<keep-alive>
<router-view v-if="$route.meta.keepAlive">
</router-view>
</keep-alive>
</template>
以下程式碼示範了第二種方法,即是在路由裏設定 meta (自定義屬性)來判斷是否要套用 keep-alive
。例子中的 A 元件,你輸入的資料後再跳回 Home,之後再次進入 A 元件,會發現資料有被緩存。但 B 元件則不會被緩存。
https://codesandbox.io/s/router-view-yu-keep-alive-mbcbf?file=/src/router/index.js
以下會用一個多步驟式表單示範如何使用 keep-alive
以及 is
屬性,做法是參考此文章提及的情景需求。
https://codesandbox.io/s/keep-alive-duo-bu-biao-dan-li-zi-21mfo?file=/src/App.vue:28-253
目前需求是:
App.vue
<component :is="`Step${currentStep}`"/>
import Step1 from "@/components/Step1.vue";
import Step2 from "@/components/Step2.vue";
import Step3 from "@/components/Step3.vue";
export default {
components: {
Step1,
Step2,
Step3,
},
data() {
return {
currentStep: 1,
};
}
}
在每個元件綁上所需的事件,用來傳送資料回到父元件 App.vue。以 Step1 元件為例:
Step1.vue
<template>
<h1>Step 1</h1>
<div>
<label for="name">Name:</label>
<input v-model="name" type="text" id="name" />
</div>
<div>
<label for="age">Age:</label>
<input v-model="age" type="number" id="age" />
</div>
<button @click="next()">Next</button>
</template>
export default {
// 有 name 屬性,keep-alive 的 include 才會有效
name: "Step1",
// 不接收父元件傳來的 inputData prop
inheritAttrs: false,
data() {
return {
name: "",
age: 0,
};
},
methods: {
next() {
this.$emit("change-step", 2);
this.$emit("update-data", {
name: this.name,
age: this.age,
});
},
},
activated() {
console.log("Step 1 is activate!");
},
deactivated() {
console.log("Step 1 is deactivated!");
},
};
有些重點要注意:
activated
和 deactivated
此兩個 lifecycle hook。inheritAttrs: false
。因為在 Step 2 元件裏沒有根節點,所以 Vue 不曉得要把父元件的所有屬性傳給 Step 2 裏哪個節點,因此解決方法有兩種,一是設定 inheritAttrs: false
,直接關掉接收父元件的屬性(因為 Step 2 沒有用到父元件傳來的 props)。二是把 <template>
裏所有內容都用一個 div
包起來(在 codesandbox 的示範 code 中會有詳細註解解釋)。'change-step'
此事件,觸發父元件修改當前的 step。按目前的需求,即是說:
在 Step 1 時:
- 要緩存 Step 1
在 Step 2 時:
- 要緩存 Step 1, Step 2
在 Step 3 時:
- 同樣要緩存 Step 1, Step 2,但不用緩存 Step 3
所以,當前 Step 的數值,以及它之前的頁面是需要被緩存。因此,可以利用此特性,使用 computed 回傳一個陣列:
computed: {
keepAliveComponents() {
let alive = [];
for (let i = 0; i < this.currentStep; i++) {
// Step 3 是確認頁面,不用緩存
if (i === 2) return alive;
alive.push(`Step${i + 1}`);
}
return alive;
}
}
因此,每次切換元件,透過動態綁定 :include="keepAliveComponents"
,計算什麼元件需要被緩存:
App.vue
<keep-alive :include="keepAliveComponents">
<component
:is="`Step${currentStep}`"
:inputData="inputData"
@change-step="changeStep"
@update-data="updateData"
/>
</keep-alive>
keep-alive
會緩存一個元件的資料狀態。is
屬性經常會與 v-bind
一起使用,作用是動態切換元件。keep-alive
接收 3 個 props,包括 include、exclude、max,指定要緩存的元件或緩存元件數量。[Vue] 跟著 Vue 闖蕩前端世界 - 13 使用 keep-alive 保留表單狀態
vue-router 之 keep-alive