From a54611b55ee81fc606a771dd1b516fac12325918 Mon Sep 17 00:00:00 2001 From: Robbin Baauw Date: Mon, 8 Jul 2019 10:52:35 +0200 Subject: [PATCH 1/2] feat(keep-alive): includes/excludes keep-alive based on key and name The keep-alive component will now also use the key of the component when checking the includes or excludes properties. fix #8028 --- src/core/components/keep-alive.js | 45 ++++--- .../component/component-keep-alive.spec.js | 125 +++++++++++++++++- 2 files changed, 145 insertions(+), 25 deletions(-) diff --git a/src/core/components/keep-alive.js b/src/core/components/keep-alive.js index fb4cf1e883b..59ef99364db 100644 --- a/src/core/components/keep-alive.js +++ b/src/core/components/keep-alive.js @@ -9,16 +9,20 @@ function getComponentName (opts: ?VNodeComponentOptions): ?string { return opts && (opts.Ctor.options.name || opts.tag) } -function matches (pattern: string | RegExp | Array, 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) +function matches (pattern: string | RegExp | Array, key: ?string, name: string): boolean { + function matchesValue(value: string) { + if (Array.isArray(pattern)) { + return pattern.indexOf(value) > -1 + } else if (typeof pattern === 'string') { + return pattern.split(',').indexOf(value) > -1 + } else if (isRegExp(pattern)) { + return pattern.test(value) + } + /* istanbul ignore next */ + return false } - /* istanbul ignore next */ - return false + + return (key && matchesValue(key)) || matchesValue(name); } function pruneCache (keepAliveInstance: any, filter: Function) { @@ -27,7 +31,7 @@ function pruneCache (keepAliveInstance: any, filter: Function) { const cachedNode: ?VNode = cache[key] if (cachedNode) { const name: ?string = getComponentName(cachedNode.componentOptions) - if (name && !filter(name)) { + if (name && !filter(key, name)) { pruneCacheEntry(cache, key, keys, _vnode) } } @@ -73,10 +77,10 @@ export default { mounted () { this.$watch('include', val => { - pruneCache(this, name => matches(val, name)) + pruneCache(this, (key, name) => matches(val, key, name)) }) this.$watch('exclude', val => { - pruneCache(this, name => !matches(val, name)) + pruneCache(this, (key, name) => !matches(val, key, name)) }) }, @@ -87,22 +91,25 @@ export default { if (componentOptions) { // check pattern const name: ?string = getComponentName(componentOptions) + + 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 + const { include, exclude } = this if ( // not included - (include && (!name || !matches(include, name))) || + (include && (!name || !matches(include, key, name))) || // excluded - (exclude && name && matches(exclude, name)) + (exclude && name && matches(exclude, key, 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 diff --git a/test/unit/features/component/component-keep-alive.spec.js b/test/unit/features/component/component-keep-alive.spec.js index a2cdf6a4f09..9a9db8b68da 100644 --- a/test/unit/features/component/component-keep-alive.spec.js +++ b/test/unit/features/component/component-keep-alive.spec.js @@ -236,7 +236,7 @@ describe('Component keep-alive', () => { }).then(done) } - it('include (string)', done => { + it('include (string, name)', done => { const vm = new Vue({ template: `
@@ -254,7 +254,26 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) - it('include (regex)', done => { + it('include (string, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + + it('include (regex, name)', done => { const vm = new Vue({ template: `
@@ -272,7 +291,26 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) - it('include (array)', done => { + it('include (regex, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + + it('include (array, name)', done => { const vm = new Vue({ template: `
@@ -290,7 +328,26 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) - it('exclude (string)', done => { + it('include (array, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + + it('exclude (string, name)', done => { const vm = new Vue({ template: `
@@ -308,7 +365,26 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) - it('exclude (regex)', done => { + it('exclude (string, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + + it('exclude (regex, name)', done => { const vm = new Vue({ template: `
@@ -326,7 +402,25 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) - it('exclude (array)', done => { + it('exclude (regex, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + it('exclude (array, name)', done => { const vm = new Vue({ template: `
@@ -344,6 +438,25 @@ describe('Component keep-alive', () => { sharedAssertions(vm, done) }) + it('exclude (array, key)', done => { + const vm = new Vue({ + template: ` +
+ + + +
+ `, + data: { + view: 'one', + ok: true + }, + components + }).$mount() + sharedAssertions(vm, done) + }) + + it('include + exclude', done => { const vm = new Vue({ template: ` From d111b52aba6df19918ed34f3da747fe94a1669e1 Mon Sep 17 00:00:00 2001 From: Robbin Baauw Date: Tue, 3 Dec 2019 18:46:12 +0100 Subject: [PATCH 2/2] fix(keep-alive): also prune when keys are not equal --- src/core/components/keep-alive.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/components/keep-alive.js b/src/core/components/keep-alive.js index 59ef99364db..652cffdddf7 100644 --- a/src/core/components/keep-alive.js +++ b/src/core/components/keep-alive.js @@ -45,7 +45,7 @@ function pruneCacheEntry ( current?: VNode ) { const cached = cache[key] - if (cached && (!current || cached.tag !== current.tag)) { + if (cached && (!current || cached.tag !== current.tag || cached.key !== current.key)) { cached.componentInstance.$destroy() } cache[key] = null