Skip to content

Commit

Permalink
fix(core): avoid mutating original children when cloning vnode
Browse files Browse the repository at this point in the history
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 vuejs#7975
  • Loading branch information
yyx990803 authored and aJean committed Aug 19, 2020
1 parent 5fc27ef commit 2c1f387
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 1 deletion.
5 changes: 4 additions & 1 deletion src/core/vdom/vnode.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
54 changes: 54 additions & 0 deletions test/unit/features/component/component-slot.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -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: '<b>{{ message }}</b>',
props: ['message']
}
let parentVm
const ParentComponent = {
template: `
<div>
<span v-if="alter">
<span><slot name="foo" /></span>
</span>
<span v-else>
<slot name="foo" />
</span>
</div>
`,
data () {
return {
alter: true
}
},
mounted () {
parentVm = this
}
}
const vm = new Vue({
template: `
<parent-component>
<span slot="foo">
<child-component :message="message" />
</span>
</parent-component>
`,
components: {
ChildComponent,
ParentComponent
},
data () {
return {
message: 1
}
}
}).$mount()
expect(vm.$el.firstChild.innerHTML).toBe('<span><span><b>1</b></span></span>')
parentVm.alter = false
waitForUpdate(() => {
vm.message = 2
}).then(() => {
expect(vm.$el.firstChild.innerHTML).toBe('<span><b>2</b></span>')
}).then(done)
})
})

0 comments on commit 2c1f387

Please sign in to comment.