]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(runtime-vapor): support functional slot in vdom component (#13576)
authorzhiyuanzmj <260480378@qq.com>
Thu, 10 Jul 2025 01:46:41 +0000 (09:46 +0800)
committerGitHub <noreply@github.com>
Thu, 10 Jul 2025 01:46:41 +0000 (18:46 -0700)
packages/runtime-core/src/helpers/renderSlot.ts
packages/runtime-vapor/__tests__/vdomInterop.spec.ts
packages/runtime-vapor/src/componentProps.ts
packages/runtime-vapor/src/vdomInterop.ts

index 152c5a4b81c13735825feb6e6d182ad08e2b0136..d5feae617a639c1eee411064142dd77189216b64 100644 (file)
@@ -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
index 08326d4d5d9babcc99c17dedffe0524557ff3998..582e67dd876fb4bf1f352adfaac45585136b2d03 100644 (file)
@@ -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', () => {})
 
index 7ee99b681708dacb852cafe3030a3d7646c4493b..b870a21b2e8e0eaec4cbee9ec91d57358d97085e 100644 (file)
@@ -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)
index e277024d73b6b22f169574ae2f049fa8013d42d5..8c1dd2cee2ba4c2ee2beddcc64025ed5909da542 100644 (file)
@@ -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
   },
 }