Просмотр исходного кода

fix incorrect context for slot content created in functional components (fix #4315)

Evan You 9 лет назад
Родитель
Сommit
326aef4a6a

+ 1 - 1
src/core/instance/lifecycle.js

@@ -146,7 +146,7 @@ export function lifecycleMixin (Vue: Class<Component>) {
     }
     // resolve slots + force update if has children
     if (hasChildren) {
-      vm.$slots = resolveSlots(renderChildren, vm._renderContext)
+      vm.$slots = resolveSlots(renderChildren, parentVnode.context)
       vm.$forceUpdate()
     }
   }

+ 4 - 2
src/core/instance/render.js

@@ -14,8 +14,9 @@ export function initRender (vm: Component) {
   vm.$vnode = null // the placeholder node in parent tree
   vm._vnode = null // the root of the child tree
   vm._staticTrees = null
-  vm._renderContext = vm.$options._parentVnode && vm.$options._parentVnode.context
-  vm.$slots = resolveSlots(vm.$options._renderChildren, vm._renderContext)
+  const parentVnode = vm.$options._parentVnode
+  const renderContext = parentVnode && parentVnode.context
+  vm.$slots = resolveSlots(vm.$options._renderChildren, renderContext)
   vm.$scopedSlots = {}
   // bind the public createElement fn to this instance
   // so that we get proper render context inside it.
@@ -256,6 +257,7 @@ export function resolveSlots (
   let name, child
   for (let i = 0, l = children.length; i < l; i++) {
     child = children[i]
+    debugger
     // named slots should only be respected if the vnode was rendered in the
     // same context.
     if ((child.context === context || child.functionalContext === context) &&

+ 30 - 0
test/unit/features/component/component-slot.spec.js

@@ -597,4 +597,34 @@ describe('Component slot', () => {
       expect(vm.$el.textContent).toBe('2foobar')
     }).then(done)
   })
+
+  // #4315
+  it('functional component passing slot content to stateful child component', done => {
+    const ComponentWithSlots = {
+      render (h) {
+        return h('div', this.$slots.slot1)
+      }
+    }
+
+    const FunctionalComp = {
+      functional: true,
+      render (h) {
+        return h(ComponentWithSlots, [h('span', { slot: 'slot1' }, 'foo')])
+      }
+    }
+
+    const vm = new Vue({
+      data: { n: 1 },
+      render (h) {
+        return h('div', [this.n, h(FunctionalComp)])
+      }
+    }).$mount()
+
+    expect(vm.$el.textContent).toBe('1foo')
+    vm.n++
+    waitForUpdate(() => {
+      // should not lose named slot
+      expect(vm.$el.textContent).toBe('2foo')
+    }).then(done)
+  })
 })