Explorar el Código

fix(runtime-vapor): apply template ref on dynamic fragment (#14471)

Jack hace 1 mes
padre
commit
2fb57c412f

+ 42 - 0
packages/runtime-vapor/__tests__/dom/templateRef.spec.ts

@@ -695,6 +695,48 @@ describe('api: template ref', () => {
     expect(html()).toBe('<div>changed</div><!--dynamic-component-->')
   })
 
+  test('components that change their dynamics', async () => {
+    const Child1 = defineVaporComponent({
+      setup(_, { expose }) {
+        expose({ setMsg: () => (msg.value = 'one') })
+        const n0 = template(`<div>1`)() as any
+        return n0
+      },
+    })
+    const Child2 = defineVaporComponent({
+      setup(_, { expose }) {
+        expose({ setMsg: () => (msg.value = 'two') })
+        const n0 = template(`<div>2`)() as any
+        return n0
+      },
+    })
+
+    const view = shallowRef(Child1)
+    const refKey = ref<any>(null)
+    const msg = ref('')
+
+    const { html } = define({
+      setup() {
+        const setRef = createTemplateRefSetter()
+        const n0 = createDynamicComponent(() => view.value) as any
+        setRef(n0, refKey)
+        return n0
+      },
+    }).render()
+
+    expect(refKey.value).toBeDefined()
+
+    expect(html()).toBe('<div>1</div><!--dynamic-component-->')
+    refKey.value.setMsg()
+    expect(msg.value).toBe('one')
+
+    view.value = Child2
+    await nextTick()
+    expect(html()).toBe('<div>2</div><!--dynamic-component-->')
+    refKey.value.setMsg()
+    expect(msg.value).toBe('two')
+  })
+
   test('should not attempt to set when variable name is same as key', () => {
     let tRef: ShallowRef
     const key = 'refKey'

+ 7 - 2
packages/runtime-vapor/src/apiTemplateRef.ts

@@ -25,7 +25,7 @@ import {
   isString,
   remove,
 } from '@vue/shared'
-import { DynamicFragment, isFragment } from './fragment'
+import { DynamicFragment, isDynamicFragment, isFragment } from './fragment'
 
 export type NodeRef =
   | string
@@ -58,6 +58,11 @@ export function createTemplateRefSetter(): setRefFn {
   const instance = currentInstance as VaporComponentInstance
   const oldRefMap = new WeakMap<RefEl, NodeRef | undefined>()
   return (el, ref, refFor, refKey) => {
+    if (isDynamicFragment(el)) {
+      ;(el.onUpdated || (el.onUpdated = [])).push(() => {
+        setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey)
+      })
+    }
     const oldRef = setRef(instance, el, ref, oldRefMap.get(el), refFor, refKey)
     oldRefMap.set(el, oldRef)
     return oldRef
@@ -116,7 +121,7 @@ export function setRef(
   }
 
   // dynamic ref changed. unset old ref
-  if (oldRef != null && oldRef !== ref) {
+  if (oldRef != null && (oldRef !== ref || isDynamicFragment(el))) {
     if (isString(oldRef)) {
       refs[oldRef] = null
       if (__DEV__ && canSetSetupRef(oldRef)) {