diff --git a/src/core/components/keep-alive.js b/src/core/components/keep-alive.js index 06f6e433..10303d2e 100644 --- a/src/core/components/keep-alive.js +++ b/src/core/components/keep-alive.js @@ -1,3 +1,5 @@ +import { callHook } from 'core/instance/lifecycle' + export default { name: 'keep-alive', _abstract: true, @@ -20,9 +22,11 @@ export default { realChild.data.keepAlive = true return rawChild }, - beforeDestroy () { + destroyed () { for (const key in this.cache) { - this.cache[key].child.$destroy() + const vnode = this.cache[key] + callHook(vnode.child, 'deactivated') + vnode.child.$destroy() } } } diff --git a/src/core/vdom/create-component.js b/src/core/vdom/create-component.js index 2549cda1..fc1441d7 100644 --- a/src/core/vdom/create-component.js +++ b/src/core/vdom/create-component.js @@ -128,10 +128,12 @@ function insert (vnode: MountedComponentVNode) { } function destroy (vnode: MountedComponentVNode) { - if (!vnode.data.keepAlive) { - vnode.child.$destroy() - } else { - callHook(vnode.child, 'deactivated') + if (!vnode.child._isDestroyed) { + if (!vnode.data.keepAlive) { + vnode.child.$destroy() + } else { + callHook(vnode.child, 'deactivated') + } } } diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index 467b3ff1..fd9da146 100644 --- a/src/core/vdom/patch.js +++ b/src/core/vdom/patch.js @@ -126,13 +126,13 @@ export function createPatchFunction (backend) { if (isDef(data)) { if (isDef(i = data.hook) && isDef(i = i.destroy)) i(vnode) for (i = 0; i < cbs.destroy.length; ++i) cbs.destroy[i](vnode) - if (isDef(i = vnode.children)) { - for (j = 0; j < vnode.children.length; ++j) { - invokeDestroyHook(vnode.children[j]) - } - } - if (isDef(i = vnode.child)) { - invokeDestroyHook(i._vnode) + } + if (isDef(i = vnode.child)) { + invokeDestroyHook(i._vnode) + } + if (isDef(i = vnode.children)) { + for (j = 0; j < vnode.children.length; ++j) { + invokeDestroyHook(vnode.children[j]) } } } diff --git a/test/unit/features/component/component-keep-alive.spec.js b/test/unit/features/component/component-keep-alive.spec.js index 8b075229..b703d5cb 100644 --- a/test/unit/features/component/component-keep-alive.spec.js +++ b/test/unit/features/component/component-keep-alive.spec.js @@ -12,14 +12,16 @@ describe('Component keep-alive', () => { created: jasmine.createSpy('one created'), mounted: jasmine.createSpy('one mounted'), activated: jasmine.createSpy('one activated'), - deactivated: jasmine.createSpy('one deactivated') + deactivated: jasmine.createSpy('one deactivated'), + destroyed: jasmine.createSpy('one destroyed') } two = { template: '
two
', created: jasmine.createSpy('two created'), mounted: jasmine.createSpy('two mounted'), activated: jasmine.createSpy('two activated'), - deactivated: jasmine.createSpy('two deactivated') + deactivated: jasmine.createSpy('two deactivated'), + destroyed: jasmine.createSpy('two destroyed') } components = { one, @@ -34,36 +36,43 @@ describe('Component keep-alive', () => { component.created.calls.count(), component.mounted.calls.count(), component.activated.calls.count(), - component.deactivated.calls.count() + component.deactivated.calls.count(), + component.destroyed.calls.count() ]).toEqual(callCounts) } it('should work', done => { const vm = new Vue({ - template: '
', + template: '
', data: { - view: 'one' + view: 'one', + ok: true }, components }).$mount() expect(vm.$el.textContent).toBe('one') - assertHookCalls(one, [1, 1, 1, 0]) - assertHookCalls(two, [0, 0, 0, 0]) + assertHookCalls(one, [1, 1, 1, 0, 0]) + assertHookCalls(two, [0, 0, 0, 0, 0]) vm.view = 'two' waitForUpdate(() => { expect(vm.$el.textContent).toBe('two') - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 0, 0]) vm.view = 'one' }).then(() => { expect(vm.$el.textContent).toBe('one') - assertHookCalls(one, [1, 1, 2, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 2, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) vm.view = 'two' }).then(() => { expect(vm.$el.textContent).toBe('two') - assertHookCalls(one, [1, 1, 2, 2]) - assertHookCalls(two, [1, 1, 2, 1]) + assertHookCalls(one, [1, 1, 2, 2, 0]) + assertHookCalls(two, [1, 1, 2, 1, 0]) + vm.ok = false // teardown + }).then(() => { + expect(vm.$el.textContent).toBe('') + assertHookCalls(one, [1, 1, 2, 3, 1]) + assertHookCalls(two, [1, 1, 2, 2, 1]) }).then(done) }) @@ -93,15 +102,15 @@ describe('Component keep-alive', () => { } }).$mount(el) expect(vm.$el.textContent).toBe('one') - assertHookCalls(one, [1, 1, 1, 0]) - assertHookCalls(two, [0, 0, 0, 0]) + assertHookCalls(one, [1, 1, 1, 0, 0]) + assertHookCalls(two, [0, 0, 0, 0, 0]) vm.view = 'two' waitForUpdate(() => { expect(vm.$el.innerHTML).toBe( '
one
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [0, 0, 0, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [0, 0, 0, 0, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
one
' @@ -112,8 +121,8 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
two
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 0, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
two
' @@ -122,16 +131,16 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
two
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 0, 0]) }).then(() => { vm.view = 'one' }).then(() => { expect(vm.$el.innerHTML).toBe( '
two
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
two
' @@ -142,8 +151,8 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
one
' ) - assertHookCalls(one, [1, 1, 2, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 2, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
one
' @@ -152,8 +161,8 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
one
' ) - assertHookCalls(one, [1, 1, 2, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 2, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) }).then(done) }) @@ -182,16 +191,16 @@ describe('Component keep-alive', () => { } }).$mount(el) expect(vm.$el.textContent).toBe('one') - assertHookCalls(one, [1, 1, 1, 0]) - assertHookCalls(two, [0, 0, 0, 0]) + assertHookCalls(one, [1, 1, 1, 0, 0]) + assertHookCalls(two, [0, 0, 0, 0, 0]) vm.view = 'two' waitForUpdate(() => { expect(vm.$el.innerHTML).toBe( '
one
' + '
two
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 0, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
one
' + @@ -216,8 +225,8 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
two
' ) - assertHookCalls(one, [1, 1, 1, 1]) - assertHookCalls(two, [1, 1, 1, 0]) + assertHookCalls(one, [1, 1, 1, 1, 0]) + assertHookCalls(two, [1, 1, 1, 0, 0]) }).then(() => { vm.view = 'one' }).then(() => { @@ -225,8 +234,8 @@ describe('Component keep-alive', () => { '
two
' + '
one
' ) - assertHookCalls(one, [1, 1, 2, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 2, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) }).thenWaitFor(nextFrame).then(() => { expect(vm.$el.innerHTML).toBe( '
two
' + @@ -251,8 +260,8 @@ describe('Component keep-alive', () => { expect(vm.$el.innerHTML).toBe( '
one
' ) - assertHookCalls(one, [1, 1, 2, 1]) - assertHookCalls(two, [1, 1, 1, 1]) + assertHookCalls(one, [1, 1, 2, 1, 0]) + assertHookCalls(two, [1, 1, 1, 1, 0]) }).then(done) }) }