diff --git a/packages/runtime-vapor/__tests__/componentSlots.spec.ts b/packages/runtime-vapor/__tests__/componentSlots.spec.ts
index 78be11ebe..868e45671 100644
--- a/packages/runtime-vapor/__tests__/componentSlots.spec.ts
+++ b/packages/runtime-vapor/__tests__/componentSlots.spec.ts
@@ -169,10 +169,12 @@ describe('component: slots', () => {
})
test('slot should be rendered correctly with slot props', async () => {
+ const src = ref('header')
+
const Comp = defineVaporComponent(() => {
const n0 = template('
')()
insert(
- createSlot('header', { title: () => 'header' }),
+ createSlot('header', { title: () => src.value }),
n0 as any as ParentNode,
)
return n0
@@ -191,6 +193,10 @@ describe('component: slots', () => {
}).render()
expect(host.innerHTML).toBe('header
')
+
+ src.value = 'footer'
+ await nextTick()
+ expect(host.innerHTML).toBe('footer
')
})
test('dynamic slot props', async () => {
@@ -263,17 +269,23 @@ describe('component: slots', () => {
$: [
() => ({
name: 'header',
- fn: (props: any) => template(props.title)(),
+ fn: (props: any) => {
+ const el = template('')()
+ renderEffect(() => {
+ setText(el, props.title)
+ })
+ return el
+ },
}),
],
})
}).render()
- expect(host.innerHTML).toBe('header
')
+ expect(host.innerHTML).toBe('header
')
val.value = 'footer'
await nextTick()
- expect(host.innerHTML).toBe('footer
')
+ expect(host.innerHTML).toBe('footer
')
})
test('dynamic slot outlet should be render correctly with slot props', async () => {
diff --git a/packages/runtime-vapor/__tests__/if.spec.ts b/packages/runtime-vapor/__tests__/if.spec.ts
index 7acff485a..a7e6266a7 100644
--- a/packages/runtime-vapor/__tests__/if.spec.ts
+++ b/packages/runtime-vapor/__tests__/if.spec.ts
@@ -15,7 +15,7 @@ import { unmountComponent } from '../src/component'
const define = makeRender()
-describe.todo('createIf', () => {
+describe('createIf', () => {
test('basic', async () => {
// mock this template:
//
diff --git a/packages/runtime-vapor/src/apiCreateIf.ts b/packages/runtime-vapor/src/apiCreateIf.ts
index 7e5661124..e40353139 100644
--- a/packages/runtime-vapor/src/apiCreateIf.ts
+++ b/packages/runtime-vapor/src/apiCreateIf.ts
@@ -1,4 +1,5 @@
-import type { BlockFn, Fragment } from './block'
+import { type BlockFn, DynamicFragment } from './block'
+import { renderEffect } from './renderEffect'
export function createIf(
condition: () => any,
@@ -6,6 +7,12 @@ export function createIf(
b2?: BlockFn,
once?: boolean,
// hydrationNode?: Node,
-): Fragment {
- return [] as any
+): DynamicFragment {
+ const frag = __DEV__ ? new DynamicFragment('if') : new DynamicFragment()
+ if (once) {
+ frag.update(condition() ? b1 : b2)
+ } else {
+ renderEffect(() => frag.update(condition() ? b1 : b2))
+ }
+ return frag
}
diff --git a/packages/runtime-vapor/src/block.ts b/packages/runtime-vapor/src/block.ts
index 65b7c70de..eccd57332 100644
--- a/packages/runtime-vapor/src/block.ts
+++ b/packages/runtime-vapor/src/block.ts
@@ -6,7 +6,7 @@ import {
unmountComponent,
} from './component'
import { createComment } from './dom/node'
-import { EffectScope } from '@vue/reactivity'
+import { EffectScope, pauseTracking, resetTracking } from '@vue/reactivity'
export type Block =
| Node
@@ -29,7 +29,7 @@ export class Fragment {
export class DynamicFragment extends Fragment {
anchor: Node
scope: EffectScope | undefined
- key: any
+ current?: BlockFn
constructor(anchorLabel?: string) {
super([])
@@ -40,10 +40,13 @@ export class DynamicFragment extends Fragment {
document.createTextNode('')
}
- update(render?: BlockFn, key: any = render): void {
- if (key === this.key) return
- this.key = key
+ update(render?: BlockFn): void {
+ if (render === this.current) {
+ return
+ }
+ this.current = render
+ pauseTracking()
const parent = this.anchor.parentNode
// teardown previous branch
@@ -60,6 +63,7 @@ export class DynamicFragment extends Fragment {
this.scope = undefined
this.nodes = []
}
+ resetTracking()
}
}
diff --git a/packages/runtime-vapor/src/componentSlots.ts b/packages/runtime-vapor/src/componentSlots.ts
index 6eb365e00..33d5ff233 100644
--- a/packages/runtime-vapor/src/componentSlots.ts
+++ b/packages/runtime-vapor/src/componentSlots.ts
@@ -109,26 +109,28 @@ export function createSlot(
fallback?: Slot,
): Block {
const instance = currentInstance as VaporComponentInstance
- const fragment = new DynamicFragment('slot')
+ const rawSlots = instance.rawSlots
+ const isDynamicName = isFunction(name)
+ const fragment = __DEV__ ? new DynamicFragment('slot') : new DynamicFragment()
const slotProps = rawProps
? new Proxy(rawProps, dynamicSlotsPropsProxyHandlers)
: EMPTY_OBJ
- // always create effect because a slot may contain dynamic root inside
- // which affects fallback
- renderEffect(() => {
- const slot = getSlot(instance.rawSlots, isFunction(name) ? name() : name)
+ const renderSlot = (name: string) => {
+ const slot = getSlot(rawSlots, name)
if (slot) {
- fragment.update(
- () => slot(slotProps) || (fallback && fallback()),
- // TODO this key needs to account for possible fallback (v-if)
- // inside the slot
- slot,
- )
+ fragment.update(() => slot(slotProps) || (fallback && fallback()))
} else {
fragment.update(fallback)
}
- })
+ }
+
+ // dynamic slot name or has dynamicSlots
+ if (isDynamicName || rawSlots.$) {
+ renderEffect(() => renderSlot(isFunction(name) ? name() : name))
+ } else {
+ renderSlot(name)
+ }
return fragment
}