|
|
@ -3,7 +3,13 @@ |
|
|
|
import { isRegExp, remove } from 'shared/util' |
|
|
|
import { getFirstComponentChild } from 'core/vdom/helpers/index' |
|
|
|
|
|
|
|
type VNodeCache = { [key: string]: ?VNode }; |
|
|
|
type CacheEntry = { |
|
|
|
name: ?string; |
|
|
|
tag: ?string; |
|
|
|
componentInstance: Component; |
|
|
|
}; |
|
|
|
|
|
|
|
type CacheEntryMap = { [key: string]: ?CacheEntry }; |
|
|
|
|
|
|
|
function getComponentName (opts: ?VNodeComponentOptions): ?string { |
|
|
|
return opts && (opts.Ctor.options.name || opts.tag) |
|
|
@ -24,9 +30,9 @@ function matches (pattern: string | RegExp | Array<string>, name: string): boole |
|
|
|
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) |
|
|
|
const entry: ?CacheEntry = cache[key] |
|
|
|
if (entry) { |
|
|
|
const name: ?string = entry.name |
|
|
|
if (name && !filter(name)) { |
|
|
|
pruneCacheEntry(cache, key, keys, _vnode) |
|
|
|
} |
|
|
@ -35,14 +41,14 @@ function pruneCache (keepAliveInstance: any, filter: Function) { |
|
|
|
} |
|
|
|
|
|
|
|
function pruneCacheEntry ( |
|
|
|
cache: VNodeCache, |
|
|
|
cache: CacheEntryMap, |
|
|
|
key: string, |
|
|
|
keys: Array<string>, |
|
|
|
current?: VNode |
|
|
|
) { |
|
|
|
const cached = cache[key] |
|
|
|
if (cached && (!current || cached.tag !== current.tag)) { |
|
|
|
cached.componentInstance.$destroy() |
|
|
|
const entry: ?CacheEntry = cache[key] |
|
|
|
if (entry && (!current || entry.tag !== current.tag)) { |
|
|
|
entry.componentInstance.$destroy() |
|
|
|
} |
|
|
|
cache[key] = null |
|
|
|
remove(keys, key) |
|
|
@ -60,6 +66,26 @@ export default { |
|
|
|
max: [String, Number] |
|
|
|
}, |
|
|
|
|
|
|
|
methods: { |
|
|
|
cacheVNode() { |
|
|
|
const { cache, keys, vnodeToCache, keyToCache } = this |
|
|
|
if (vnodeToCache) { |
|
|
|
const { tag, componentInstance, componentOptions } = vnodeToCache |
|
|
|
cache[keyToCache] = { |
|
|
|
name: getComponentName(componentOptions), |
|
|
|
tag, |
|
|
|
componentInstance, |
|
|
|
} |
|
|
|
keys.push(keyToCache) |
|
|
|
// prune oldest entry
|
|
|
|
if (this.max && keys.length > parseInt(this.max)) { |
|
|
|
pruneCacheEntry(cache, keys[0], keys, this._vnode) |
|
|
|
} |
|
|
|
this.vnodeToCache = null |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
|
|
|
|
created () { |
|
|
|
this.cache = Object.create(null) |
|
|
|
this.keys = [] |
|
|
@ -72,6 +98,7 @@ export default { |
|
|
|
}, |
|
|
|
|
|
|
|
mounted () { |
|
|
|
this.cacheVNode() |
|
|
|
this.$watch('include', val => { |
|
|
|
pruneCache(this, name => matches(val, name)) |
|
|
|
}) |
|
|
@ -80,6 +107,10 @@ export default { |
|
|
|
}) |
|
|
|
}, |
|
|
|
|
|
|
|
updated () { |
|
|
|
this.cacheVNode() |
|
|
|
}, |
|
|
|
|
|
|
|
render () { |
|
|
|
const slot = this.$slots.default |
|
|
|
const vnode: VNode = getFirstComponentChild(slot) |
|
|
@ -109,12 +140,9 @@ export default { |
|
|
|
remove(keys, key) |
|
|
|
keys.push(key) |
|
|
|
} else { |
|
|
|
cache[key] = vnode |
|
|
|
keys.push(key) |
|
|
|
// prune oldest entry
|
|
|
|
if (this.max && keys.length > parseInt(this.max)) { |
|
|
|
pruneCacheEntry(cache, keys[0], keys, this._vnode) |
|
|
|
} |
|
|
|
// delay setting the cache until update
|
|
|
|
this.vnodeToCache = vnode |
|
|
|
this.keyToCache = key |
|
|
|
} |
|
|
|
|
|
|
|
vnode.data.keepAlive = true |
|
|
|