1,介紹和作用
<!-- 非活躍的組件將會被緩存! -->
<keep-alive>
<component :is="activeComponent" />
</keep-alive>
1,是一個內(nèi)部組件,用于緩存組件實(shí)例。在組件切換時(shí),不用重新創(chuàng)建而是使用緩存中的組件實(shí)例。
- 可以避免創(chuàng)建組件的開銷。
- 可以保留組件狀態(tài)。
2,有3個屬性:
-
include
和exclude
屬性,可以控制哪些組件進(jìn)入緩存。 -
max
屬性可以設(shè)置最大緩存數(shù),當(dāng)緩存的實(shí)例超過該數(shù)時(shí),vue會移除最久沒有使用的組件緩存。
<!-- 以英文逗號分隔的字符串 -->
<keep-alive include="Comp1,Comp2">
<component :is="view" />
</keep-alive>
<!-- 數(shù)組 -->
<keep-alive :include="['Comp1', 'Comp2']">
<component :is="view" />
</keep-alive>
3,受 keep-alive
影響,內(nèi)部所有嵌套的組件都有2個生命周期函數(shù)。activated
和 deactivated
。第1次 activated
是在 mounted
之后。
4,當(dāng)嵌套組件是 <router-view>
時(shí),緩存的是路由對應(yīng)的組件。
因?yàn)?
<router-view>
是函數(shù)式組件,只有一個目的,生成虛擬DOM。它沒有狀態(tài),不生成實(shí)例。有穿透的效果。
<keep-alive>
<router-view></router-view>
</keep-alive>
2,原理
源碼
keep-alive
在內(nèi)部維護(hù)了一個緩存對象和 keys
數(shù)組:
// keep-alive 組件的生命周期函數(shù)
created () {
this.cache = Object.create(null)
this.keys = []
}
-
keys
數(shù)組記錄當(dāng)前緩存組件的key
,如果組件沒有指定,則會自動為組件生成唯一的key
。 -
cache
對象以key
為鍵,vnode 為值,來緩存組件對應(yīng)的虛擬 DOM。
在 keep-alive
組件的 render
函數(shù)中,大致邏輯:
判斷當(dāng)前渲染的 vnode 是否有對應(yīng)的緩存,有則從緩存中讀取對應(yīng)組件實(shí)例,沒有則將其緩存。當(dāng)緩存數(shù)量 > max 時(shí),會移除掉 keys
數(shù)組的第1個元素。
// 更新邏輯其實(shí)在 update 函數(shù)中,這里結(jié)合在一起容易理解。
render(){
const slot = this.$slots.default; // 獲取默認(rèn)插槽
const vnode = getFirstComponentChild(slot); // 得到插槽中的第一個組件的 vnode
const name = getComponentName(vnode.componentOptions); // 獲取組件名字
const { cache, keys } = this; // 獲取當(dāng)前的緩存對象和key數(shù)組
const key = ...; // 獲取組件的key值,若沒有,會按照規(guī)則自動生成
if (cache[key]) {
// 有緩存
// 關(guān)鍵:重用組件實(shí)例
vnode.componentInstance = cache[key].componentInstance
remove(keys, key); // 刪除key
// 將 key加入到數(shù)組末尾,這樣是為了保證最近使用的組件在數(shù)組中靠后,反之靠前
keys.push(key);
} else {
// 無緩存,則進(jìn)行緩存
cache[key] = vnode
keys.push(key)
if (this.max && keys.length > parseInt(this.max)) {
// 超過最大緩存數(shù)量,移除第一個key對應(yīng)的緩存
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
return vnode || (slot && slot[0])
}
注意到,render()
返回的就是插槽中的第一個組件的 vnode。所以頁面上顯示的也就是這個子組件。
3,使用場景
在后臺管理系統(tǒng)中比較常見,比如有2種情況就會用到:
- 側(cè)邊欄的菜單,一般對應(yīng)的是路由。切換頁面(路由)時(shí)想保留之前的頁面信息。
- 列表頁進(jìn)詳情頁時(shí),想保留列表頁信息,因?yàn)榱斜砜赡苁峭ㄟ^輸入框等多個過濾條件得到的,如果從詳情頁返回列表頁再次操作會比較繁瑣。
這2種情況,都可以做成 tab 選項(xiàng)卡。
3.1,效果展示
3.2,實(shí)現(xiàn)思路
首先維護(hù)一個【tab選項(xiàng)卡】的狀態(tài),比如放到 Vuex 中。不放到組件內(nèi)部,是因?yàn)椴缓檬褂?,因?yàn)榭赡懿恢箓?cè)邊欄會添加 tab,其他地方可能也會添加頁面到 tab 選項(xiàng)卡。
export default new Vuex.Store({
modules: {
tabs: {
namespaced: true,
state: {
pageNames: [] // 選項(xiàng)卡的頁面
},
mutations: {
addPage(state, newPageName) {
if (!state.pageNames.includes(newPageName)) {
state.pageNames.push(newPageName)
}
},
removePage(state, pageName) {
const index = state.pageNames.indexOf(pageName)
if (index >= 0) {
state.pageNames.splice(index, 1)
}
}
}
}
}
})
其他的看代碼就一目了然了:(省略了CSS)文章來源:http://www.zghlxwxcb.cn/news/detail-823789.html
<template>
<div>
<!-- 固定在頁面左側(cè) -->
<div>
<h1>側(cè)邊欄</h1>
<ul>
<router-link
v-for="item in $router.options.routes"
:key="item.path"
tag="li"
:to="{ name: item.name }"
active-class="blue"
>
<span>{{ item.name }}</span>
<button @click="handleAddPage(item.name)">+</button>
</router-link>
</ul>
</div>
<!-- 頁面內(nèi)容區(qū)域 -->
<div>
<!-- 固定在頁面頂部,左側(cè)和側(cè)邊欄對齊 -->
<div v-if="$store.state.tabs.pageNames.length">
<span>tab選項(xiàng)卡:</span>
<ul>
<router-link
v-for="pageName in $store.state.tabs.pageNames"
:key="pageName"
tag="li"
active-class="green"
:to="{ name: pageName }"
>
<span>{{ pageName }}</span>
<button @click="handleRemovePage(pageName)">x</button>
</router-link>
</ul>
</div>
<!-- 頁面內(nèi)容展示區(qū)域 -->
<keep-alive :include="$store.state.tabs.pageNames">
<router-view></router-view>
</keep-alive>
</div>
</div>
</template>
<script>
export default {
methods: {
handleAddPage(pageName) {
this.$store.commit('tabs/addPage', pageName)
},
handleRemovePage(pageName) {
this.$store.commit('tabs/removePage', pageName)
}
}
}
</script>
以上。文章來源地址http://www.zghlxwxcb.cn/news/detail-823789.html
到了這里,關(guān)于Vue2 - keep-alive 作用和原理的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!