Vue3 - 快取(Cache)組件
tags: Vue
category: Front-End
description: Vue3 - 快取(Cache)組件<KeepAlive>
created_at: 2022/07/22 14:00:00
回到 手把手開始寫 Vue3
前言
這次要提的是快取組件,先提一下因為是快取,他並不是真的每次都重新掛上新的,所以可能會有舊的資料在上面,要自己記得做處理。
快取組件
首先先來試試組件的快取
要快取組件的話會使用 <KeepAlive>
這個內建組件,這個組件可以讓包住的組件做動態切換的時候做緩存。
然後要注意的點是: 這個組件只能有一個子元素
也就是說它的使用方式是這樣
<KeepAlive>
<component :is="targetComponent" />
</KeepAlive>
或是如果你硬要的話,也可以這樣
<KeepAlive>
<A v-if="targetComponent === 'A'"></A>
<B v-else-if="targetComponent === 'B'"></B>
<C v-else-if="targetComponent === 'C'"></C>
<!-- ... -->
</KeepAlive>
補充: 下面這樣是不行的喔!
<KeepAlive>
<A v-if="targetComponent === 'A'"></A>
<B v-if="targetComponent === 'B'"></B>
<C v-if="targetComponent === 'C'"></C>
<D v-if="targetComponent === 'D'"></D>
<E v-if="targetComponent === 'E'"></E>
<F v-if="targetComponent === 'F'"></F>
</KeepAlive>
雖然看也知道他其實只會同時符合一個條件,但是他在編譯的時候就會噴掉了。
因為在一般情況下確實有可能使用 v-if
同時有多個成立,但 else-if
就不同了。
指定哪些(要/不要)快取
可以用 include
與 exclude
兩個屬性來定義,可以放入逗號分隔的字串、陣列或是一個正規表達式 RegExp
。
這邊比較簡單,就直接貼官方的範例吧:
<!-- comma-delimited string -->
<KeepAlive include="a,b">
<component :is="view" />
</KeepAlive>
<!-- regex (use `v-bind`) -->
<KeepAlive :include="/a|b/">
<component :is="view" />
</KeepAlive>
<!-- Array (use `v-bind`) -->
<KeepAlive :include="['a', 'b']">
<component :is="view" />
</KeepAlive>
指定快取數量
使用 max
屬性指定快取的數量,而他的行為是 LRU Cache,如果數量超過就會把最近最少使用的刪掉。
舉個例子:
<script setup>
import { shallowRef } from "vue";
import A from "./components/A.vue";
import B from "./components/B.vue";
import C from "./components/C.vue";
import D from "./components/D.vue";
import E from "./components/E.vue";
import F from "./components/F.vue";
const components = [A, B, C, D, E, F];
const targetComponent = shallowRef(components[0]);
</script>
<template>
<div class="flex">
<button
class="bg-blue-500 text-white px-4 py-2 m-2"
v-for="component in components"
:key="component.__name"
@click="targetComponent = component"
>
{{ component.__name }}
</button>
</div>
<hr />
<KeepAlive max="4">
<component :is="targetComponent" />
</KeepAlive>
</template>
然後那個 components/A.vue
到 components/F.vue
都長成這樣
<script setup>
import { onMounted, onUnmounted } from "vue";
onMounted(() => {
console.log("onMounted", "A");
});
onUnmounted(() => {
console.log("onUnmounted", "A");
});
</script>
<template>
<div>Component A</div>
<div>
<input class="border" type="text" />
</div>
</template>
只要修改對應的地方,分辨得出來誰是誰就好。
然後因為上面設定的 max="4"
,所以當你照著這個順序戳
A -> B -> C -> D(到此時空間已滿) -> E(A會被彈出) -> B -> F(這時C會被彈出)
onMounted A
onMounted B
onMounted C
onMounted D
onUnmounted A
onMounted E
onUnmounted C
onMounted F
如果要講更細的話,一樣的範例:
空間 4
,順序 A->B->C->D->E->B->F
生命週期
看上面的範例會發現被快取的組件就不會再次觸發 onMounted
與 onUnmounted
了,那還是想知道他被掛上去跟被拿掉呢?
可以使用 onActivated
與 onDeactivated
我自己玩下來的感覺是這樣的,
當 onMounted
的時候會一起觸發 onActivated
。
但是 onDeactivated
跟 onUnmounted
不一定會一起觸發。
因為 onMounted
與 onActivated
都是被掛上去的時候。
而 onDeactivated
跟 onUnmounted
雖然都是被拿掉的時候,但是 onUnmounted
是在快取中也不見了才會被呼叫到。
一樣以上面的順序戳一次 A->B->C->D->E->B->F
我只幫元件 A
加上 onActivated
與 onDeactivated
,會看到輸出:
onMounted A
onActivated A
onDeactivated A
onMounted B
onMounted C
onMounted D
onUnmounted A
onMounted E
onUnmounted C
onMounted F
你會看到說 onMounted
與 onActivated
一起。
然後 onUnmounted
並沒有跟 onDeactivated
一起輸出。