Просмотр исходного кода

fix(compiler-vapor): wrap handler values in functions for dynamic v-on (#14218)

edison 4 месяцев назад
Родитель
Сommit
1e3e1ef2bf

+ 1 - 1
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformElement.spec.ts.snap

@@ -291,7 +291,7 @@ exports[`compiler: element transform > component > v-on="obj" 1`] = `
 export function render(_ctx) {
   const _component_Foo = _resolveComponent("Foo")
   const n0 = _createComponentWithFallback(_component_Foo, { $: [
-    () => (_toHandlers(_ctx.obj))
+    () => (_toHandlers(_ctx.obj, false, true))
   ] }, null, true)
   return n0
 }"

+ 1 - 1
packages/compiler-vapor/__tests__/transforms/__snapshots__/transformSlotOutlet.spec.ts.snap

@@ -181,7 +181,7 @@ export function render(_ctx) {
   const n0 = _createSlot("default", {
     onClick: () => _ctx.foo,
     $: [
-      () => (_toHandlers(_ctx.bar)),
+      () => (_toHandlers(_ctx.bar, false, true)),
       { baz: () => (_ctx.qux) }
     ]
   })

+ 1 - 1
packages/compiler-vapor/__tests__/transforms/transformElement.spec.ts

@@ -364,7 +364,7 @@ describe('compiler: element transform', () => {
       const { code, ir } = compileWithElementTransform(`<Foo v-on="obj" />`)
       expect(code).toMatchSnapshot()
       expect(code).contains(`[
-    () => (_toHandlers(_ctx.obj))
+    () => (_toHandlers(_ctx.obj, false, true))
   ]`)
       expect(ir.block.dynamic.children[0].operation).toMatchObject({
         type: IRNodeTypes.CREATE_COMPONENT_NODE,

+ 7 - 1
packages/compiler-vapor/src/generators/component.ts

@@ -219,7 +219,13 @@ function genDynamicProps(
         expr = genMulti(DELIMITERS_OBJECT, genProp(p, context))
       else {
         expr = genExpression(p.value, context)
-        if (p.handler) expr = genCall(helper('toHandlers'), expr)
+        if (p.handler)
+          expr = genCall(
+            helper('toHandlers'),
+            expr,
+            `false`, // preserveCaseIfNecessary: false, not needed for component
+            `true`, // wrap handler values in functions
+          )
       }
     }
     frags.push(['() => (', ...expr, ')'])

+ 2 - 1
packages/runtime-core/src/helpers/toHandlers.ts

@@ -8,6 +8,7 @@ import { warn } from '../warning'
 export function toHandlers(
   obj: Record<string, any>,
   preserveCaseIfNecessary?: boolean,
+  needWrap?: boolean,
 ): Record<string, any> {
   const ret: Record<string, any> = {}
   if (__DEV__ && !isObject(obj)) {
@@ -19,7 +20,7 @@ export function toHandlers(
       preserveCaseIfNecessary && /[A-Z]/.test(key)
         ? `on:${key}`
         : toHandlerKey(key)
-    ] = obj[key]
+    ] = needWrap ? () => obj[key] : obj[key]
   }
   return ret
 }

+ 11 - 5
packages/runtime-vapor/__tests__/componentEmits.spec.ts

@@ -87,7 +87,6 @@ describe('component: emit', () => {
     expect(fooSpy).toHaveBeenCalledTimes(1)
   })
 
-  // #3527
   test('trigger mixed case handlers', () => {
     const { render } = define({
       setup(_, { emit }) {
@@ -100,10 +99,17 @@ describe('component: emit', () => {
     const fooSpy = vi.fn()
     const barSpy = vi.fn()
     render(
-      toHandlers({
-        'test-event': () => fooSpy,
-        testEvent: () => barSpy,
-      }),
+      // v-on="{ testEvent: handler }"
+      // will be compiled to
+      // toHandlers({ testEvent: handler }, false, true)
+      toHandlers(
+        {
+          'test-event': fooSpy,
+          testEvent: barSpy,
+        },
+        false,
+        true,
+      ),
     )
     expect(fooSpy).toHaveBeenCalledTimes(1)
     expect(barSpy).toHaveBeenCalledTimes(1)