From 097f6229dffc34af452b106ad2a3b58845588807 Mon Sep 17 00:00:00 2001 From: Evan You Date: Sat, 1 Dec 2018 17:05:36 -0500 Subject: [PATCH] fix(core): avoid mutating original children when cloning vnode The on-demand clone strategy introduced in 956756b mutates the owner array of the cloned vnode. This causes the newly cloned vnode to be destroyed when the parent node is destroyed. This is fixed by cloning the children array when cloning a vnode. fix #7975 --- src/core/vdom/vnode.js | 5 +- .../features/component/component-slot.spec.js | 54 +++++++++++++++++++ 2 files changed, 58 insertions(+), 1 deletion(-) diff --git a/src/core/vdom/vnode.js b/src/core/vdom/vnode.js index 0e3e2e9e63..bdc17e9f97 100644 --- a/src/core/vdom/vnode.js +++ b/src/core/vdom/vnode.js @@ -90,7 +90,10 @@ export function cloneVNode (vnode: VNode): VNode { const cloned = new VNode( vnode.tag, vnode.data, - vnode.children, + // #7975 + // clone children array to avoid mutating original in case of cloning + // a child. + vnode.children && vnode.children.slice(), vnode.text, vnode.elm, vnode.context, diff --git a/test/unit/features/component/component-slot.spec.js b/test/unit/features/component/component-slot.spec.js index e667a46ef8..75b5254601 100644 --- a/test/unit/features/component/component-slot.spec.js +++ b/test/unit/features/component/component-slot.spec.js @@ -886,4 +886,58 @@ describe('Component slot', () => { expect(vm.$el.textContent).toBe('foo') }).then(done) }) + + // #7975 + it('should update named slot correctly when its position in the tree changed', done => { + const ChildComponent = { + template: '{{ message }}', + props: ['message'] + } + let parentVm + const ParentComponent = { + template: ` +
+ + + + + + +
+ `, + data () { + return { + alter: true + } + }, + mounted () { + parentVm = this + } + } + const vm = new Vue({ + template: ` + + + + + + `, + components: { + ChildComponent, + ParentComponent + }, + data () { + return { + message: 1 + } + } + }).$mount() + expect(vm.$el.firstChild.innerHTML).toBe('1') + parentVm.alter = false + waitForUpdate(() => { + vm.message = 2 + }).then(() => { + expect(vm.$el.firstChild.innerHTML).toBe('2') + }).then(done) + }) })