Kaynağa Gözat

fix: also clone component slot children during deepClone

fix #6891, fix #6915
Evan You 8 yıl önce
ebeveyn
işleme
1cf02efda2

+ 5 - 2
src/core/vdom/patch.js

@@ -673,9 +673,12 @@ export function createPatchFunction (backend) {
           // create an empty node and replace it
           oldVnode = emptyNodeAt(oldVnode)
         }
+
         // replacing existing element
         const oldElm = oldVnode.elm
         const parentElm = nodeOps.parentNode(oldElm)
+
+        // create new node
         createElm(
           vnode,
           insertedVnodeQueue,
@@ -686,9 +689,8 @@ export function createPatchFunction (backend) {
           nodeOps.nextSibling(oldElm)
         )
 
+        // update parent placeholder node element, recursively
         if (isDef(vnode.parent)) {
-          // component root element replaced.
-          // update parent placeholder node element, recursively
           let ancestor = vnode.parent
           const patchable = isPatchable(vnode)
           while (ancestor) {
@@ -717,6 +719,7 @@ export function createPatchFunction (backend) {
           }
         }
 
+        // destroy old node
         if (isDef(parentElm)) {
           removeVnodes(parentElm, [oldVnode], 0, 0)
         } else if (isDef(oldVnode.tag)) {

+ 9 - 3
src/core/vdom/vnode.js

@@ -86,6 +86,7 @@ export function createTextVNode (val: string | number) {
 // multiple renders, cloning them avoids errors when DOM manipulations rely
 // on their elm reference.
 export function cloneVNode (vnode: VNode, deep?: boolean): VNode {
+  const componentOptions = vnode.componentOptions
   const cloned = new VNode(
     vnode.tag,
     vnode.data,
@@ -93,7 +94,7 @@ export function cloneVNode (vnode: VNode, deep?: boolean): VNode {
     vnode.text,
     vnode.elm,
     vnode.context,
-    vnode.componentOptions,
+    componentOptions,
     vnode.asyncFactory
   )
   cloned.ns = vnode.ns
@@ -101,8 +102,13 @@ export function cloneVNode (vnode: VNode, deep?: boolean): VNode {
   cloned.key = vnode.key
   cloned.isComment = vnode.isComment
   cloned.isCloned = true
-  if (deep && vnode.children) {
-    cloned.children = cloneVNodes(vnode.children)
+  if (deep) {
+    if (vnode.children) {
+      cloned.children = cloneVNodes(vnode.children, true)
+    }
+    if (componentOptions && componentOptions.children) {
+      componentOptions.children = cloneVNodes(componentOptions.children, true)
+    }
   }
   return cloned
 }

+ 8 - 4
test/unit/features/component/component-slot.spec.js

@@ -686,6 +686,7 @@ describe('Component slot', () => {
     expect(vm.$el.innerHTML).toBe('<div>default<span>foo</span></div>')
   })
 
+  // #6372, #6915
   it('should handle nested components in slots properly', done => {
     const TestComponent = {
       template: `
@@ -706,7 +707,10 @@ describe('Component slot', () => {
           <test-component ref="test">
             <div>
               <foo/>
-            </div><bar/>
+            </div>
+            <bar>
+              <foo/>
+            </bar>
           </test-component>
         </div>
       `,
@@ -716,16 +720,16 @@ describe('Component slot', () => {
           template: `<div>foo</div>`
         },
         bar: {
-          template: `<div>bar</div>`
+          template: `<div>bar<slot/></div>`
         }
       }
     }).$mount()
 
-    expect(vm.$el.innerHTML).toBe(`<b><div><div>foo</div></div><div>bar</div></b>`)
+    expect(vm.$el.innerHTML).toBe(`<b><div><div>foo</div></div> <div>bar<div>foo</div></div></b>`)
 
     vm.$refs.test.toggleEl = false
     waitForUpdate(() => {
-      expect(vm.$el.innerHTML).toBe(`<i><div><div>foo</div></div><div>bar</div></i>`)
+      expect(vm.$el.innerHTML).toBe(`<i><div><div>foo</div></div> <div>bar<div>foo</div></div></i>`)
     }).then(done)
   })