vue keep-alive元件使用
keep-alive是Vue.js的一個內建元件。<keep-alive> 包裹動態元件時,會快取不活動的元件例項,而不是銷燬它們。它自身不會渲染一個 DOM 元素,也不會出現在父元件鏈中。 當元件在 <keep-alive> 內被切換,它的 activated 和 deactivated 這兩個生命週期鉤子函式將會被對應執行。它提供了include與exclude兩個屬性,允許元件有條件地進行快取。
舉個栗子
-
<keep-alive>
-
<router-view v-if="$route.meta.keepAlive"></router-view>
-
</keep-alive>
-
<router-view v-if="!$route.meta.keepAlive"></router-view>
-
複製程式碼
切換按鈕
在點選button時候,兩個input會發生切換,但是這時候這兩個輸入框的狀態會被快取起來,input標籤中的內容不會因為元件的切換而消失。
-
* include - 字串或正則表示式。只有匹配的元件會被快取。
-
* exclude - 字串或正則表示式。任何匹配的元件都不會被快取。
-
複製程式碼
-
<keep-alive include="a">
-
<component></component>
-
</keep-alive>
-
複製程式碼
只快取元件別民name為a的元件
-
<keep-alive exclude="a">
-
<component></component>
-
</keep-alive>
-
複製程式碼
除了name為a的元件,其他都快取下來
生命週期鉤子
生命鉤子keep-alive提供了兩個生命鉤子,分別是activated與deactivated。
因為keep-alive會將元件儲存在記憶體中,並不會銷燬以及重新建立,所以不會重新呼叫元件的created等方法,需要用activated與deactivated這兩個生命鉤子來得知當前元件是否處於活動狀態。
深入keep-alive元件實現
檢視vue--keep-alive元件原始碼可以得到以下資訊
created鉤子會建立一個cache物件,用來作為快取容器,儲存vnode節點。
-
props: {
-
include: patternTypes,
-
exclude: patternTypes,
-
max: [String, Number]
-
},
-
created () {
-
// 建立快取物件
-
this.cache = Object.create(null)
-
// 建立一個key別名陣列(元件name)
-
this.keys = []
-
},
-
複製程式碼
destroyed鉤子則在元件被銷燬的時候清除cache快取中的所有元件例項。
-
destroyed () {
-
/* 遍歷銷燬所有快取的元件例項*/
-
for (const key in this.cache) {
-
pruneCacheEntry(this.cache, key, this.keys)
-
}
-
},
-
複製程式碼
:::demo
-
render () {
-
/* 獲取插槽 */
-
const slot = this.$slots.default
-
/* 根據插槽獲取第一個元件元件 */
-
const vnode: VNode = getFirstComponentChild(slot)
-
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
-
if (componentOptions) {
-
// 獲取元件的名稱(是否設定了元件名稱name,沒有則返回元件標籤名稱)
-
const name: ?string = getComponentName(componentOptions)
-
// 解構物件賦值常量
-
const { include, exclude } = this
-
if ( /* name不在inlcude中或者在exlude中則直接返回vnode */
-
// not included
-
(include && (!name || !matches(include, name))) ||
-
// excluded
-
(exclude && name && matches(exclude, name))
-
) {
-
return vnode
-
}
-
const { cache, keys } = this
-
const key: ?string = vnode.key == null
-
// same constructor may get registered as different local components
-
// so cid alone is not enough (#3269)
-
? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
-
: vnode.key
-
if (cache[key]) { // 判斷當前是否有快取,有則取快取的例項,無則進行快取
-
vnode.componentInstance = cache[key].componentInstance
-
// make current key freshest
-
remove(keys, key)
-
keys.push(key)
-
} else {
-
cache[key] = vnode
-
keys.push(key)
-
// 判斷是否設定了最大快取例項數量,超過則刪除最老的資料,
-
if (this.max && keys.length > parseInt(this.max)) {
-
pruneCacheEntry(cache, keys[0], keys, this._vnode)
-
}
-
}
-
// 給vnode打上快取標記
-
vnode.data.keepAlive = true
-
}
-
return vnode || (slot && slot[0])
-
}
-
// 銷燬例項
-
function pruneCacheEntry (
-
cache: VNodeCache,
-
key: string,
-
keys: Array<string>,
-
current?: VNode
-
) {
-
const cached = cache[key]
-
if (cached && (!current || cached.tag !== current.tag)) {
-
cached.componentInstance.$destroy()
-
}
-
cache[key] = null
-
remove(keys, key)
-
}
-
// 快取
-
function pruneCache (keepAliveInstance: any, filter: Function) {
-
const { cache, keys, _vnode } = keepAliveInstance
-
for (const key in cache) {
-
const cachedNode: ?VNode = cache[key]
-
if (cachedNode) {
-
const name: ?string = getComponentName(cachedNode.componentOptions)
-
// 元件name 不符合filler條件, 銷燬例項,移除cahe
-
if (name && !filter(name)) {
-
pruneCacheEntry(cache, key, keys, _vnode)
-
}
-
}
-
}
-
}
-
// 篩選過濾函式
-
function matches (pattern: string | RegExp | Array<string>, name: string): boolean {
-
if (Array.isArray(pattern)) {
-
return pattern.indexOf(name) > -1
-
} else if (typeof pattern === 'string') {
-
return pattern.split(',').indexOf(name) > -1
-
} else if (isRegExp(pattern)) {
-
return pattern.test(name)
-
}
-
/* istanbul ignore next */
-
return false
-
}
-
// 檢測 include 和 exclude 資料的變化,實時寫入讀取快取或者刪除
-
mounted () {
-
this.$watch('include', val => {
-
pruneCache(this, name => matches(val, name))
-
})
-
this.$watch('exclude', val => {
-
pruneCache(this, name => !matches(val, name))
-
})
-
},
-
複製程式碼
:::
通過檢視Vue原始碼可以看出,keep-alive預設傳遞3個屬性,include 、exclude、max, max 最大可快取的長度
結合原始碼我們可以實現一個可配置快取的router-view
-
<!--exclude - 字串或正則表示式。任何匹配的元件都不會被快取。-->
-
<!--TODO 匹配首先檢查元件自身的 name 選項,如果 name 選項不可用,則匹配它的區域性註冊名稱-->
-
<keep-alive :exclude="keepAliveConf.value">
-
<router-view class="child-view" :key="$route.fullPath"></router-view>
-
</keep-alive>
-
<!-- 或者 -->
-
<keep-alive :include="keepAliveConf.value">
-
<router-view class="child-view" :key="$route.fullPath"></router-view>
-
</keep-alive>
-
<!-- 具體使用 include 還是exclude 根據專案是否需要快取的頁面數量多少來決定-->
-
複製程式碼
建立一個keepAliveConf.js 放置需要匹配的元件名
-
// 路由元件命名集合
-
var arr = ['component1', 'component2'];
-
export default {value: routeList.join()};
-
複製程式碼
配置重置快取的全域性方法
-
import keepAliveConf from 'keepAliveConf.js'
-
Vue.mixin({
-
methods: {
-
// 傳入需要重置的元件名字
-
resetKeepAive(name) {
-
const conf = keepAliveConf.value;
-
let arr = keepAliveConf.value.split(',');
-
if (name && typeof name === 'string') {
-
let i = arr.indexOf(name);
-
if (i > -1) {
-
arr.splice(i, 1);
-
keepAliveConf.value = arr.join();
-
setTimeout(() => {
-
keepAliveConf.value = conf
-
}, 500);
-
}
-
}
-
},
-
}
-
})
-
複製程式碼
在合適的時機呼叫呼叫this.resetKeepAive(name),觸發keep-alive銷燬元件例項;
Vue.js內部將DOM節點抽象成了一個個的VNode節點,keep-alive元件的快取也是基於VNode節點的而不是直接儲存DOM結構。它將滿足條件的元件在cache物件中快取起來,在需要重新渲染的時候再將vnode節點從cache物件中取出並渲染。
作者:walker-design
連結:https://juejin.im/post/5b4320f9f265da0f7f4488f6
來源:掘金
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。
轉載於:https://blog.csdn.net/sinat_17775997/article/details/80993644