Bläddra i källkod

feat(runtime-vapor): support functional slot in vdom component (#13576)

zhiyuanzmj 9 månader sedan
förälder
incheckning
d5adf95dda

+ 1 - 1
packages/runtime-core/src/helpers/renderSlot.ts

@@ -35,7 +35,7 @@ export function renderSlot(
   let slot = slots[name]
 
   // vapor slots rendered in vdom
-  if (slot && slots._vapor) {
+  if (slot && (slot as any).__vapor) {
     const ret = (openBlock(), createBlock(VaporSlot, props))
     ret.vs = { slot, fallback }
     return ret

+ 60 - 2
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -1,4 +1,4 @@
-import { defineComponent, h } from '@vue/runtime-dom'
+import { createVNode, defineComponent, h, renderSlot } from '@vue/runtime-dom'
 import { makeInteropRender } from './_utils'
 import { createComponent, defineVaporComponent } from '../src'
 
@@ -9,7 +9,65 @@ describe('vdomInterop', () => {
 
   describe.todo('emit', () => {})
 
-  describe.todo('slots', () => {})
+  describe('slots', () => {
+    test('basic', () => {
+      const VDomChild = defineComponent({
+        setup(_, { slots }) {
+          return () => renderSlot(slots, 'default')
+        },
+      })
+
+      const VaporChild = defineVaporComponent({
+        setup() {
+          return createComponent(
+            VDomChild as any,
+            null,
+            {
+              default: () => document.createTextNode('default slot'),
+            },
+            true,
+          )
+        },
+      })
+
+      const { html } = define({
+        setup() {
+          return () => h(VaporChild as any)
+        },
+      }).render()
+
+      expect(html()).toBe('default slot')
+    })
+
+    test('functional slot', () => {
+      const VDomChild = defineComponent({
+        setup(_, { slots }) {
+          return () => createVNode(slots.default!)
+        },
+      })
+
+      const VaporChild = defineVaporComponent({
+        setup() {
+          return createComponent(
+            VDomChild as any,
+            null,
+            {
+              default: () => document.createTextNode('default slot'),
+            },
+            true,
+          )
+        },
+      })
+
+      const { html } = define({
+        setup() {
+          return () => h(VaporChild as any)
+        },
+      }).render()
+
+      expect(html()).toBe('default slot')
+    })
+  })
 
   describe.todo('provide', () => {})
 

+ 1 - 1
packages/runtime-vapor/src/componentProps.ts

@@ -185,7 +185,7 @@ export function getAttrFromRawProps(rawProps: RawProps, key: string): unknown {
       source = dynamicSources[i]
       isDynamic = isFunction(source)
       source = isDynamic ? (source as Function)() : source
-      if (hasOwn(source, key)) {
+      if (source && hasOwn(source, key)) {
         const value = isDynamic ? source[key] : source[key]()
         if (merged) {
           merged.push(value)

+ 4 - 4
packages/runtime-vapor/src/vdomInterop.ts

@@ -134,11 +134,11 @@ const vaporSlotPropsProxyHandler: ProxyHandler<
 
 const vaporSlotsProxyHandler: ProxyHandler<any> = {
   get(target, key) {
-    if (key === '_vapor') {
-      return target
-    } else {
-      return target[key]
+    const slot = target[key]
+    if (isFunction(slot)) {
+      slot.__vapor = true
     }
+    return slot
   },
 }