您好,登錄后才能下訂單哦!
本篇文章為大家展示了keep-alive組件的緩存原理是什么,內(nèi)容簡明扼要并且容易理解,絕對能使你眼前一亮,通過這篇文章的詳細(xì)介紹希望你能有所收獲。
官方API介紹和用法
<keep-alive> 包裹動態(tài)組件時,會緩存不活動的組件實(shí)例,而不是銷毀它們。
和 <transition> 相似,<keep-alive> 是一個抽象組件:它自身不會渲染一個 DOM 元素,也不會出現(xiàn)在組件的父組件鏈中。
當(dāng)組件在 <keep-alive> 內(nèi)被切換,它的 activated 和 deactivated 這兩個生命周期鉤子函數(shù)將會被對應(yīng)執(zhí)行。
官網(wǎng)的例子是 tab 切換保存了用戶的操作,實(shí)際中還可能遇到從列表頁跳轉(zhuǎn)去了詳情頁,再跳轉(zhuǎn)回列表頁需要保存用戶進(jìn)行過的篩選操作,這就需要用到 <keep-alive>,這樣也能避免重新渲染,提高頁面性能。
// keep-alive組件搭配動態(tài)組件的用法,還要其他的用法參見官網(wǎng) <keep-alive include="['componentNameA', 'componentNameB']" exclude="'componentNameC'" :max="10"> <component :is="view"></component> </keep-alive>
include - 字符串或正則表達(dá)式或數(shù)組,name匹配上的組件會被緩存
exclude - 字符串或正則表達(dá)式或數(shù)組,name匹配上的組件都不會被緩存
max - 字符串或數(shù)字,緩存組件實(shí)例的最大數(shù),最久沒有被訪問的實(shí)例會被銷毀掉
注意:
<keep-alive> 只渲染其直系的一個組件,因此若在 <keep-alive> 中用 v-for,則其不會工作,若多條件判斷有多個符合條件也同理不工作。
include 和 exclude 匹配時,首先檢查組件的 name 選項(xiàng),若 name 選項(xiàng)不可用,則匹配它的局部注冊名稱 (即父組件 components 選項(xiàng)的鍵值)。匿名組件不能被匹配。
<keep-alive> 不會在函數(shù)式組件中正常工作,因?yàn)樗鼈儧]有緩存實(shí)例。
先貼一張?jiān)创a圖
總共125行,收起來一看其實(shí)東西也比較少。前面是引入一些需要用到的方法,然后定義了一些 keep-alive 組件自己會用到的一些方法,最后就是向外暴露一個 name 為 keep-alive 的組件選項(xiàng),這些選項(xiàng)除了 abstract 外,其他的我們都比較熟悉了,其中, render 函數(shù)就是緩存原理最重要的部分,也能看出 keep-alive 組件是一個函數(shù)式組件。
// isRegExp函數(shù)判斷是不是正則表達(dá)式,remove移除數(shù)組中的某一個成員 // getFirstComponentChild獲取VNode數(shù)組的第一個有效組件 import { isRegExp, remove } from 'shared/util' import { getFirstComponentChild } from 'core/vdom/helpers/index' type VNodeCache = { [key: string]: ?VNode }; // 緩存組件VNode的緩存類型 // 通過組件的name或組件tag來獲取組件名(上面注意的第二點(diǎn)) function getComponentName (opts: ?VNodeComponentOptions): ?string { return opts && (opts.Ctor.options.name || opts.tag) } // 判斷include或exclude跟組件的name是否匹配成功 function matches (pattern: string | RegExp | Array<string>, name: string): boolean { if (Array.isArray(pattern)) { return pattern.indexOf(name) > -1 // include或exclude是數(shù)組的情況 } else if (typeof pattern === 'string') { return pattern.split(',').indexOf(name) > -1 // include或exclude是字符串的情況 } else if (isRegExp(pattern)) { return pattern.test(name) // include或exclude是正則表達(dá)式的情況 } return false // 都沒匹配上(上面注意的二三點(diǎn)) } // 銷毀緩存 function pruneCache (keepAliveInstance: any, filter: Function) { const { cache, keys, _vnode } = keepAliveInstance // keep-alive組件實(shí)例 for (const key in cache) { const cachedNode: ?VNode = cache[key] // 已經(jīng)被緩存的組件 if (cachedNode) { const name: ?string = getComponentName(cachedNode.componentOptions) // 若name存在且不能跟include或exclude匹配上就銷毀這個已經(jīng)緩存的組件 if (name && !filter(name)) { pruneCacheEntry(cache, key, keys, _vnode) } } } } // 銷毀緩存的入口 function pruneCacheEntry ( cache: VNodeCache, key: string, keys: Array<string>, current?: VNode ) { const cached = cache[key] // 被緩存過的組件 // “已經(jīng)被緩存的組件是否繼續(xù)被緩存” 有變動時 // 若組件被緩存命中過且當(dāng)前組件不存在或緩存命中組件的tag和當(dāng)前組件的tag不相等 if (cached && (!current || cached.tag !== current.tag)) { // 說明現(xiàn)在這個組件不需要被繼續(xù)緩存,銷毀這個組件實(shí)例 cached.componentInstance.$destroy() } cache[key] = null // 把緩存中這個組件置為null remove(keys, key) // 把這個組件的key移除出keys數(shù)組 } // 示例類型 const patternTypes: Array<Function> = [String, RegExp, Array] // 向外暴露keep-alive組件的一些選項(xiàng) export default { name: 'keep-alive', // 組件名 abstract: true, // keep-alive是抽象組件 // 用keep-alive組件時傳入的三個props props: { include: patternTypes, exclude: patternTypes, max: [String, Number] }, created () { this.cache = Object.create(null) // 存儲需要緩存的組件 this.keys = [] // 存儲每個需要緩存的組件的key,即對應(yīng)this.cache對象中的鍵值 }, // 銷毀keep-alive組件的時候,對緩存中的每個組件執(zhí)行銷毀 destroyed () { for (const key in this.cache) { pruneCacheEntry(this.cache, key, this.keys) } }, // keep-alive組件掛載時監(jiān)聽include和exclude的變化,條件滿足時就銷毀已緩存的組件 mounted () { this.$watch('include', val => { pruneCache(this, name => matches(val, name)) }) this.$watch('exclude', val => { pruneCache(this, name => !matches(val, name)) }) }, // 重點(diǎn)來了 render () { const slot = this.$slots.default // keep-alive組件的默認(rèn)插槽 const vnode: VNode = getFirstComponentChild(slot) // 獲取默認(rèn)插槽的第一個有效組件 // 如果vnode存在就取vnode的選項(xiàng) const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions if (componentOptions) { //獲取第一個有效組件的name const name: ?string = getComponentName(componentOptions) const { include, exclude } = this // props傳遞來的include和exclude if ( // 若include存在且name不存在或name未匹配上 (include && (!name || !matches(include, name))) || // 若exclude存在且name存在或name匹配上 (exclude && name && matches(exclude, name)) ) { return vnode // 說明不用緩存,直接返回這個組件進(jìn)行渲染 } // 匹配上就需要進(jìn)行緩存操作 const { cache, keys } = this // keep-alive組件的緩存組件和緩存組件對應(yīng)的key // 獲取第一個有效組件的key const key: ?string = vnode.key == null // 同一個構(gòu)造函數(shù)可以注冊為不同的本地組件 // 所以僅靠cid是不夠的,進(jìn)行拼接一下 ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '') : vnode.key // 如果這個組件命中緩存 if (cache[key]) { // 這個組件的實(shí)例用緩存中的組件實(shí)例替換 vnode.componentInstance = cache[key].componentInstance // 更新當(dāng)前key在keys中的位置 remove(keys, key) // 把當(dāng)前key從keys中移除 keys.push(key) // 再放到keys的末尾 } else { // 如果沒有命中緩存,就把這個組件加入緩存中 cache[key] = vnode keys.push(key) // 把這個組件的key放到keys的末尾 // 如果緩存中的組件個數(shù)超過傳入的max,銷毀緩存中的LRU組件 if (this.max && keys.length > parseInt(this.max)) { pruneCacheEntry(cache, keys[0], keys, this._vnode) } } vnode.data.keepAlive = true // 設(shè)置這個組件的keepAlive屬性為true } // 若第一個有效的組件存在,但其componentOptions不存在,就返回這個組件進(jìn)行渲染 // 或若也不存在有效的第一個組件,但keep-alive組件的默認(rèn)插槽存在,就返回默認(rèn)插槽的第一個組件進(jìn)行渲染 return vnode || (slot && slot[0]) } }
上述內(nèi)容就是keep-alive組件的緩存原理是什么,你們學(xué)到知識或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識儲備,歡迎關(guān)注億速云行業(yè)資訊頻道。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。