fix(templateRef): add support for dynamic components

This commit is contained in:
daiwei 2025-04-08 14:52:33 +08:00
parent 9ab8e4c0c9
commit 305a0e8b89
2 changed files with 49 additions and 2 deletions

View File

@ -1,10 +1,13 @@
import type { NodeRef } from '../../src/apiTemplateRef'
import {
child,
createComponent,
createDynamicComponent,
createFor,
createIf,
createSlot,
createTemplateRefSetter,
defineVaporComponent,
insert,
renderEffect,
template,
@ -19,7 +22,8 @@ import {
useTemplateRef,
watchEffect,
} from '@vue/runtime-dom'
import { setElementText } from '../../src/dom/prop'
import { setElementText, setText } from '../../src/dom/prop'
import type { VaporComponent } from '../../src/component'
const define = makeRender()
@ -676,6 +680,39 @@ describe('api: template ref', () => {
expect(r!.value).toBe(n)
})
test('work with dynamic component', async () => {
const Child = defineVaporComponent({
setup(_, { expose }) {
const msg = ref('one')
expose({ setMsg: (m: string) => (msg.value = m) })
const n0 = template(`<div> </div>`)() as any
const x0 = child(n0) as any
renderEffect(() => setText(x0, msg.value))
return n0
},
})
const views: Record<string, VaporComponent> = { child: Child }
const view = ref('child')
const refKey = ref<InstanceType<any>>(null)
const { html } = define({
setup() {
const setRef = createTemplateRefSetter()
const n0 = createDynamicComponent(() => views[view.value]) as any
setRef(n0, refKey)
return n0
},
}).render()
expect(html()).toBe('<div>one</div><!--dynamic-component-->')
expect(refKey.value).toBeDefined()
refKey.value.setMsg('changed')
await nextTick()
expect(html()).toBe('<div>changed</div><!--dynamic-component-->')
})
// TODO: can not reproduce in Vapor
// // #2078
// test('handling multiple merged refs', async () => {

View File

@ -20,6 +20,7 @@ import {
isString,
remove,
} from '@vue/shared'
import { DynamicFragment } from './block'
export type NodeRef = string | Ref | ((ref: Element) => void)
export type RefEl = Element | VaporComponentInstance
@ -49,7 +50,7 @@ export function setRef(
if (!instance || instance.isUnmounted) return
const setupState: any = __DEV__ ? instance.setupState || {} : null
const refValue = isVaporComponent(el) ? getExposed(el) || el : el
const refValue = getRefValue(el)
const refs =
instance.refs === EMPTY_OBJ ? (instance.refs = {}) : instance.refs
@ -143,3 +144,12 @@ export function setRef(
}
return ref
}
const getRefValue = (el: RefEl) => {
if (isVaporComponent(el)) {
return getExposed(el) || el
} else if (el instanceof DynamicFragment) {
return getRefValue(el.nodes as RefEl)
}
return el
}