Explorar el Código

fix(runtime-vapor): keep vdom child attrs in sync with vapor parent updates (#14521)

edison hace 3 meses
padre
commit
11cb1126eb

+ 41 - 0
packages/runtime-vapor/__tests__/vdomInterop.spec.ts

@@ -1329,6 +1329,47 @@ describe('vdomInterop', () => {
       // fn should be called once
       expect(fn).toHaveBeenCalledTimes(1)
     })
+
+    it('should update attrs passed from vapor parent to vdom child', async () => {
+      const msg = ref('foo')
+
+      const VDomChild = defineComponent({
+        setup(_, { attrs }) {
+          return () =>
+            h(
+              'div',
+              {
+                'data-msg': attrs['data-msg'] as string,
+              },
+              attrs['data-msg'] as string,
+            )
+        },
+      })
+
+      const VaporChild = defineVaporComponent({
+        setup() {
+          return createComponent(
+            VDomChild as any,
+            {
+              'data-msg': () => msg.value,
+            },
+            null,
+            true,
+          )
+        },
+      })
+
+      const { html } = define({
+        setup() {
+          return () => h(VaporChild as any)
+        },
+      }).render()
+
+      expect(html()).toBe('<div data-msg="foo">foo</div>')
+      msg.value = 'bar'
+      await nextTick()
+      expect(html()).toBe('<div data-msg="bar">bar</div>')
+    })
   })
 
   describe('async component', () => {

+ 25 - 6
packages/runtime-vapor/src/vdomInterop.ts

@@ -584,12 +584,31 @@ function createVDOMComponent(
     // ensure props are shallow reactive to align with VDOM behavior.
     instance.props = shallowReactive(wrapper.props)
 
-    const attrs = (instance.attrs = createInternalObject())
-    for (const key in wrapper.attrs) {
-      if (!isEmitListener(instance.emitsOptions, key)) {
-        attrs[key] = wrapper.attrs[key]
-      }
-    }
+    const attrs = createInternalObject()
+    const isFilteredEmit = (key: string | symbol): boolean =>
+      typeof key === 'string' && isEmitListener(instance.emitsOptions, key)
+    instance.attrs = new Proxy(attrs, {
+      get(_, key: string | symbol) {
+        if (isFilteredEmit(key)) return
+        return wrapper.attrs[key as any]
+      },
+      has(_, key: string | symbol) {
+        return !isFilteredEmit(key) && key in wrapper.attrs
+      },
+      ownKeys() {
+        return Reflect.ownKeys(wrapper.attrs).filter(
+          key => !isFilteredEmit(key),
+        )
+      },
+      getOwnPropertyDescriptor(_, key: string | symbol) {
+        if (!isFilteredEmit(key) && key in wrapper.attrs) {
+          return {
+            enumerable: true,
+            configurable: true,
+          }
+        }
+      },
+    })
 
     instance.slots =
       wrapper.slots === EMPTY_OBJ