Browse Source

refactor: simplify event handler

三咲智子 Kevin Deng 2 years ago
parent
commit
38865c7ca1

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

@@ -203,7 +203,7 @@ export function render(_ctx) {
   _prepend(n4, n1)
   _insert(n2, n4, n5)
   _append(n4, n3)
-  _on(n4, "click", (...args) => (_ctx.handleClick && _ctx.handleClick(...args)))
+  _on(n4, "click", () => _ctx.handleClick)
   _renderEffect(() => {
     _setText(n1, _ctx.count)
     _setText(n2, _ctx.count)

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

@@ -11,7 +11,7 @@ export function render(_ctx) {
   const n1 = _createFor(() => (_ctx.items), (_block) => {
     const n2 = t0()
     const { 0: [n3],} = _children(n2)
-    _on(n3, "click", $event => (_ctx.remove(_block.s[0])))
+    _on(n3, "click", () => $event => (_ctx.remove(_block.s[0])))
     _renderEffect(() => {
       const [item] = _block.s
       _setText(n3, item)

+ 132 - 65
packages/compiler-vapor/__tests__/transforms/__snapshots__/vOn.spec.ts.snap

@@ -8,7 +8,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "fooBar", (...args) => (_ctx.onMount && _ctx.onMount(...args)))
+  _on(n1, "fooBar", () => _ctx.onMount)
   return n0
 }"
 `;
@@ -21,7 +21,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", (...args) => (_ctx.a['b' + _ctx.c] && _ctx.a['b' + _ctx.c](...args)))
+  _on(n1, "click", () => _ctx.a['b' + _ctx.c])
   return n0
 }"
 `;
@@ -34,7 +34,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, _ctx.event, (...args) => (_ctx.handler && _ctx.handler(...args))))
+  _renderEffect(() => _on(n1, _ctx.event, () => _ctx.handler))
   return n0
 }"
 `;
@@ -47,7 +47,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, _ctx.event(_ctx.foo), (...args) => (_ctx.handler && _ctx.handler(...args))))
+  _renderEffect(() => _on(n1, _ctx.event(_ctx.foo), () => _ctx.handler))
   return n0
 }"
 `;
@@ -60,41 +60,80 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, _ctx.event, (...args) => (_ctx.handler && _ctx.handler(...args))))
+  _renderEffect(() => _on(n1, _ctx.event, () => _ctx.handler))
   return n0
 }"
 `;
 
 exports[`v-on > event modifier 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on, withKeys as _withKeys } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<a></a><form></form><a></a><div></div><div></div><a></a><div></div><input><input><input><input><input><input><input><input><input><input><input><input><input><input><input>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1], 1: [n2], 2: [n3], 3: [n4], 4: [n5], 5: [n6], 6: [n7], 7: [n8], 8: [n9], 9: [n10], 10: [n11], 11: [n12], 12: [n13], 13: [n14], 14: [n15], 15: [n16], 16: [n17], 17: [n18], 18: [n19], 19: [n20], 20: [n21], 21: [n22],} = _children(n0)
-  _on(n1, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop"]))
-  _on(n2, "submit", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["prevent"]))
-  _on(n3, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["stop", "prevent"]))
-  _on(n4, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]))
-  _on(n5, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { capture: true })
-  _on(n6, "click", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { once: true })
-  _on(n7, "scroll", (...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), { passive: true })
-  _on(n8, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
-  _on(n9, "click", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
-  _on(n10, "mouseup", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["middle"]))
-  _on(n11, "contextmenu", _withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["right"]))
-  _on(n12, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["enter"]))
-  _on(n13, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["tab"]))
-  _on(n14, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["delete"]))
-  _on(n15, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["esc"]))
-  _on(n16, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["space"]))
-  _on(n17, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["up"]))
-  _on(n18, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["down"]))
-  _on(n19, "keyup", _withKeys((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["left"]))
-  _on(n20, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle"]))
-  _on(n21, "keyup", _withModifiers((...args) => (_ctx.submit && _ctx.submit(...args)), ["middle", "self"]))
-  _on(n22, "keyup", _withKeys(_withModifiers((...args) => (_ctx.handleEvent && _ctx.handleEvent(...args)), ["self"]), ["enter"]))
+  _on(n1, "click", () => _ctx.handleEvent, undefined, {
+    modifiers: ["stop"]
+  })
+  _on(n2, "submit", () => _ctx.handleEvent, undefined, {
+    modifiers: ["prevent"]
+  })
+  _on(n3, "click", () => _ctx.handleEvent, undefined, {
+    modifiers: ["stop", "prevent"]
+  })
+  _on(n4, "click", () => _ctx.handleEvent, undefined, {
+    modifiers: ["self"]
+  })
+  _on(n5, "click", () => _ctx.handleEvent, { capture: true })
+  _on(n6, "click", () => _ctx.handleEvent, { once: true })
+  _on(n7, "scroll", () => _ctx.handleEvent, { passive: true })
+  _on(n8, "contextmenu", () => _ctx.handleEvent, undefined, {
+    modifiers: ["right"]
+  })
+  _on(n9, "click", () => _ctx.handleEvent, undefined, {
+    modifiers: ["left"]
+  })
+  _on(n10, "mouseup", () => _ctx.handleEvent, undefined, {
+    modifiers: ["middle"]
+  })
+  _on(n11, "contextmenu", () => _ctx.handleEvent, undefined, {
+    modifiers: ["right"]
+  })
+  _on(n12, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["enter"]
+  })
+  _on(n13, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["tab"]
+  })
+  _on(n14, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["delete"]
+  })
+  _on(n15, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["esc"]
+  })
+  _on(n16, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["space"]
+  })
+  _on(n17, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["up"]
+  })
+  _on(n18, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["down"]
+  })
+  _on(n19, "keyup", () => _ctx.handleEvent, undefined, {
+    keys: ["left"]
+  })
+  _on(n20, "keyup", () => _ctx.submit, undefined, {
+    modifiers: ["middle"]
+  })
+  _on(n21, "keyup", () => _ctx.submit, undefined, {
+    modifiers: ["middle", "self"]
+  })
+  _on(n22, "keyup", () => _ctx.handleEvent, undefined, {
+    modifiers: ["self"],
+    keys: ["enter"]
+  })
   return n0
 }"
 `;
@@ -107,7 +146,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", e => _ctx.foo(e))
+  _on(n1, "click", () => e => _ctx.foo(e))
   return n0
 }"
 `;
@@ -120,7 +159,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => (_ctx.foo($event)))
+  _on(n1, "click", () => $event => (_ctx.foo($event)))
   return n0
 }"
 `;
@@ -133,7 +172,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => {_ctx.foo($event);_ctx.bar()})
+  _on(n1, "click", () => $event => {_ctx.foo($event);_ctx.bar()})
   return n0
 }"
 `;
@@ -146,7 +185,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => {_ctx.i++;_ctx.foo($event)})
+  _on(n1, "click", () => $event => {_ctx.i++;_ctx.foo($event)})
   return n0
 }"
 `;
@@ -159,7 +198,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", (e: any): any => _ctx.foo(e))
+  _on(n1, "click", () => (e: any): any => _ctx.foo(e))
   return n0
 }"
 `;
@@ -172,7 +211,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", 
+  _on(n1, "click", () => 
       $event => {
         _ctx.foo($event)
       }
@@ -189,7 +228,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => _ctx.foo($event))
+  _on(n1, "click", () => $event => _ctx.foo($event))
   return n0
 }"
 `;
@@ -202,7 +241,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", (...args) => (_ctx.a['b' + _ctx.c] && _ctx.a['b' + _ctx.c](...args)))
+  _on(n1, "click", () => _ctx.a['b' + _ctx.c])
   return n0
 }"
 `;
@@ -215,7 +254,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => {
+  _on(n1, "click", () => $event => {
 _ctx.foo();
 _ctx.bar()
 })
@@ -231,7 +270,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => {_ctx.foo();_ctx.bar()})
+  _on(n1, "click", () => $event => {_ctx.foo();_ctx.bar()})
   return n0
 }"
 `;
@@ -244,99 +283,118 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", (...args) => (_ctx.foo.bar && _ctx.foo.bar(...args)))
+  _on(n1, "click", () => _ctx.foo.bar)
   return n0
 }"
 `;
 
 exports[`v-on > should not wrap keys guard if no key modifier is present 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "keyup", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["exact"]))
+  _on(n1, "keyup", () => _ctx.test, undefined, {
+    modifiers: ["exact"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should support multiple events and modifiers options w/ prefixIdentifiers: true 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on, withKeys as _withKeys } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop"]))
-  _on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["enter"]))
+  _on(n1, "click", () => _ctx.test, undefined, {
+    modifiers: ["stop"]
+  })
+  _on(n1, "keyup", () => _ctx.test, undefined, {
+    keys: ["enter"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should support multiple modifiers and event options w/ prefixIdentifiers: true 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop", "prevent"]), { capture: true, once: true })
+  _on(n1, "click", () => _ctx.test, { capture: true, once: true }, {
+    modifiers: ["stop", "prevent"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.middle 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "mouseup", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["middle"]))
+  _on(n1, "mouseup", () => _ctx.test, undefined, {
+    modifiers: ["middle"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.middle 2`] = `
-"import { template as _template, children as _children, renderEffect as _renderEffect, withModifiers as _withModifiers, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["middle"])))
+  _renderEffect(() => {
+    _on(n1, (_ctx.event) === "click" ? "mouseup" : (_ctx.event), () => _ctx.test, undefined, {
+      modifiers: ["middle"]
+    })})
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.right 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "contextmenu", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["right"]))
+  _on(n1, "contextmenu", () => _ctx.test, undefined, {
+    modifiers: ["right"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should transform click.right 2`] = `
-"import { template as _template, children as _children, renderEffect as _renderEffect, withModifiers as _withModifiers, withKeys as _withKeys, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), _withKeys(_withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["right"]), ["right"])))
+  _renderEffect(() => {
+    _on(n1, (_ctx.event) === "click" ? "contextmenu" : (_ctx.event), () => _ctx.test, undefined, {
+      modifiers: ["right"],
+      keys: ["right"]
+    })})
   return n0
 }"
 `;
@@ -349,20 +407,24 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", $event => (_ctx.i++))
+  _on(n1, "click", () => $event => (_ctx.i++))
   return n0
 }"
 `;
 
 exports[`v-on > should wrap both for dynamic key event w/ left/right modifiers 1`] = `
-"import { template as _template, children as _children, renderEffect as _renderEffect, withModifiers as _withModifiers, withKeys as _withKeys, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, renderEffect as _renderEffect, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _renderEffect(() => _on(n1, _ctx.e, _withKeys(_withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["left"]), ["left"])))
+  _renderEffect(() => {
+    _on(n1, _ctx.e, () => _ctx.test, undefined, {
+      modifiers: ["left"],
+      keys: ["left"]
+    })})
   return n0
 }"
 `;
@@ -373,35 +435,40 @@ const t0 = _template("<div></div><div></div><div></div>")
 (() => {
   const n0 = t0()
   const { 0: [n1], 1: [n2], 2: [n3],} = _children(n0)
-  _on(n1, "click", $event => (x.value=_unref(y)))
-  _on(n2, "click", $event => (x.value++))
-  _on(n3, "click", $event => ({ x: x.value } = _unref(y)))
+  _on(n1, "click", () => $event => (x.value=_unref(y)))
+  _on(n2, "click", () => $event => (x.value++))
+  _on(n3, "click", () => $event => ({ x: x.value } = _unref(y)))
   return n0
 })()"
 `;
 
 exports[`v-on > should wrap keys guard for keyboard events or dynamic events 1`] = `
-"import { template as _template, children as _children, withModifiers as _withModifiers, withKeys as _withKeys, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "keydown", _withKeys(_withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop", "ctrl"]), ["a"]), { capture: true })
+  _on(n1, "keydown", () => _ctx.test, { capture: true }, {
+    modifiers: ["stop", "ctrl"],
+    keys: ["a"]
+  })
   return n0
 }"
 `;
 
 exports[`v-on > should wrap keys guard for static key event w/ left/right modifiers 1`] = `
-"import { template as _template, children as _children, withKeys as _withKeys, on as _on } from 'vue/vapor';
+"import { template as _template, children as _children, on as _on } from 'vue/vapor';
 
 const t0 = _template("<div></div>")
 
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["left"]))
+  _on(n1, "keyup", () => _ctx.test, undefined, {
+    keys: ["left"]
+  })
   return n0
 }"
 `;
@@ -414,7 +481,7 @@ const t0 = _template("<div></div>")
 export function render(_ctx) {
   const n0 = t0()
   const { 0: [n1],} = _children(n0)
-  _on(n1, "click", (...args) => (_ctx.handleClick && _ctx.handleClick(...args)))
+  _on(n1, "click", () => _ctx.handleClick)
   return n0
 }"
 `;

+ 27 - 27
packages/compiler-vapor/__tests__/transforms/vOn.spec.ts

@@ -167,7 +167,7 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains('_on(n1, "click", $event => (_ctx.i++))')
+    expect(code).contains('_on(n1, "click", () => $event => (_ctx.i++))')
   })
 
   test('should wrap in unref if identifier is setup-maybe-ref w/ inline: true', () => {
@@ -186,10 +186,12 @@ describe('v-on', () => {
 
     expect(vaporHelpers).contains('unref')
     expect(helpers.size).toBe(0)
-    expect(code).contains('_on(n1, "click", $event => (x.value=_unref(y)))')
-    expect(code).contains('_on(n2, "click", $event => (x.value++))')
     expect(code).contains(
-      '_on(n3, "click", $event => ({ x: x.value } = _unref(y)))',
+      '_on(n1, "click", () => $event => (x.value=_unref(y)))',
+    )
+    expect(code).contains('_on(n2, "click", () => $event => (x.value++))')
+    expect(code).contains(
+      '_on(n3, "click", () => $event => ({ x: x.value } = _unref(y)))',
     )
   })
 
@@ -207,7 +209,9 @@ describe('v-on', () => {
     // should wrap with `{` for multiple statements
     // in this case the return value is discarded and the behavior is
     // consistent with 2.x
-    expect(code).contains('_on(n1, "click", $event => {_ctx.foo();_ctx.bar()})')
+    expect(code).contains(
+      '_on(n1, "click", () => $event => {_ctx.foo();_ctx.bar()})',
+    )
   })
 
   test('should handle multi-line statement', () => {
@@ -225,7 +229,7 @@ describe('v-on', () => {
     // in this case the return value is discarded and the behavior is
     // consistent with 2.x
     expect(code).contains(
-      '_on(n1, "click", $event => {\n_ctx.foo();\n_ctx.bar()\n})',
+      '_on(n1, "click", () => $event => {\n_ctx.foo();\n_ctx.bar()\n})',
     )
   })
 
@@ -243,7 +247,9 @@ describe('v-on', () => {
 
     expect(code).matchSnapshot()
     // should NOT prefix $event
-    expect(code).contains('_on(n1, "click", $event => (_ctx.foo($event)))')
+    expect(code).contains(
+      '_on(n1, "click", () => $event => (_ctx.foo($event)))',
+    )
   })
 
   test('multiple inline statements w/ prefixIdentifiers: true', () => {
@@ -261,7 +267,7 @@ describe('v-on', () => {
     expect(code).matchSnapshot()
     // should NOT prefix $event
     expect(code).contains(
-      '_on(n1, "click", $event => {_ctx.foo($event);_ctx.bar()})',
+      '_on(n1, "click", () => $event => {_ctx.foo($event);_ctx.bar()})',
     )
   })
 
@@ -276,7 +282,7 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains('_on(n1, "click", $event => _ctx.foo($event))')
+    expect(code).contains('_on(n1, "click", () => $event => _ctx.foo($event))')
   })
 
   test('should NOT wrap as function if expression is already function expression (with Typescript)', () => {
@@ -293,7 +299,9 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains('_on(n1, "click", (e: any): any => _ctx.foo(e))')
+    expect(code).contains(
+      '_on(n1, "click", () => (e: any): any => _ctx.foo(e))',
+    )
   })
 
   test('should NOT wrap as function if expression is already function expression (with newlines)', () => {
@@ -359,9 +367,7 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains(
-      `_on(n1, "click", (...args) => (_ctx.a['b' + _ctx.c] && _ctx.a['b' + _ctx.c](...args)))`,
-    )
+    expect(code).contains(`_on(n1, "click", () => _ctx.a['b' + _ctx.c])`)
   })
 
   test('function expression w/ prefixIdentifiers: true', () => {
@@ -377,7 +383,7 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains('_on(n1, "click", e => _ctx.foo(e))')
+    expect(code).contains('_on(n1, "click", () => e => _ctx.foo(e))')
   })
 
   test('should error if no expression AND no modifier', () => {
@@ -463,8 +469,6 @@ describe('v-on', () => {
     )
 
     expect(vaporHelpers).contains('on')
-    expect(vaporHelpers).contains('withModifiers')
-
     expect(ir.operation).toMatchObject([
       {
         type: IRNodeTypes.SET_EVENT,
@@ -483,8 +487,7 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains('_withModifiers')
-    expect(code).contains('["stop", "prevent"]')
+    expect(code).contains('modifiers: ["stop", "prevent"]')
     expect(code).contains('{ capture: true, once: true }')
   })
 
@@ -536,12 +539,11 @@ describe('v-on', () => {
     ])
 
     expect(code).matchSnapshot()
-    expect(code).contains(
-      '_on(n1, "click", _withModifiers((...args) => (_ctx.test && _ctx.test(...args)), ["stop"]))',
-    )
-    expect(code).contains(
-      '_on(n1, "keyup", _withKeys((...args) => (_ctx.test && _ctx.test(...args)), ["enter"]))',
-    )
+    expect(code).contains(`_on(n1, "click", () => _ctx.test, undefined`)
+    expect(code).contains(`modifiers: ["stop"]`)
+
+    expect(code).contains(`_on(n1, "keyup", () => _ctx.test, undefined`)
+    expect(code).contains(`keys: ["enter"]`)
   })
 
   test('should wrap keys guard for keyboard events or dynamic events', () => {
@@ -723,8 +725,6 @@ describe('v-on', () => {
     })
 
     expect(code).matchSnapshot()
-    expect(code).contains(
-      `_on(n1, "click", (...args) => (_ctx.foo.bar && _ctx.foo.bar(...args)))`,
-    )
+    expect(code).contains(`_on(n1, "click", () => _ctx.foo.bar)`)
   })
 })

+ 39 - 35
packages/compiler-vapor/src/generators/event.ts

@@ -1,5 +1,12 @@
 import { isMemberExpression } from '@vue/compiler-dom'
-import { type CodeFragment, type CodegenContext, NEWLINE } from '../generate'
+import {
+  type CodeFragment,
+  type CodegenContext,
+  INDENT_END,
+  INDENT_START,
+  NEWLINE,
+  buildCodeFragment,
+} from '../generate'
 import type { SetEventIRNode } from '../ir'
 import { genExpression } from './expression'
 
@@ -15,13 +22,24 @@ export function genSetEvent(
   const { keys, nonKeys, options } = oper.modifiers
 
   const name = genName()
-  const handler = genFinalizedHandler()
-  const opt =
-    !!options.length && `{ ${options.map(v => `${v}: true`).join(', ')} }`
+  const handler = genEventHandler()
+  const modifierOptions = genModifierOptions()
+  const handlerOptions = options.length
+    ? `{ ${options.map(v => `${v}: true`).join(', ')} }`
+    : modifierOptions
+      ? 'undefined'
+      : undefined
 
   return [
     NEWLINE,
-    ...call(vaporHelper('on'), `n${oper.element}`, name, handler, opt),
+    ...call(
+      vaporHelper('on'),
+      `n${oper.element}`,
+      name,
+      handler,
+      handlerOptions,
+      modifierOptions,
+    ),
   ]
 
   function genName(): CodeFragment[] {
@@ -42,55 +60,41 @@ export function genSetEvent(
     if (exp && exp.content.trim()) {
       const isMemberExp = isMemberExpression(exp.content, ctxOptions)
       const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content))
-      const hasMultipleStatements = exp.content.includes(`;`)
 
       if (isInlineStatement) {
         const expr = context.withId(() => genExpression(exp, context), {
           $event: null,
         })
+        const hasMultipleStatements = exp.content.includes(`;`)
         return [
-          '$event => ',
+          '() => $event => ',
           hasMultipleStatements ? '{' : '(',
           ...expr,
           hasMultipleStatements ? '}' : ')',
         ]
       } else {
-        const expr = genExpression(exp, context)
-        if (isMemberExp) {
-          return ['(...args) => (', ...expr, ' && ', ...expr, '(...args))']
-        } else {
-          return expr
-        }
+        return ['() => ', ...genExpression(exp, context)]
       }
     }
-    return '() => {}'
-  }
 
-  function genFinalizedHandler() {
-    let expr = genEventHandler()
+    return ['() => {}']
+  }
 
+  function genModifierOptions() {
+    const hasOptions = nonKeys.length || keys.length
+    if (!hasOptions) return
+    const [frag, push] = buildCodeFragment('{', INDENT_START)
     if (nonKeys.length) {
-      expr = [
-        vaporHelper('withModifiers'),
-        '(',
-        ...expr,
-        ', ',
-        genArrayExpression(nonKeys),
-        ')',
-      ]
+      push(NEWLINE, 'modifiers: ', genArrayExpression(nonKeys))
+    }
+    if (keys.length && nonKeys.length) {
+      push(',')
     }
     if (keys.length) {
-      expr = [
-        vaporHelper('withKeys'),
-        '(',
-        ...expr,
-        ', ',
-        genArrayExpression(keys),
-        ')',
-      ]
+      push(NEWLINE, 'keys: ', genArrayExpression(keys))
     }
-
-    return expr
+    push(INDENT_END, NEWLINE, '}')
+    return frag
   }
 }
 

+ 1 - 1
packages/runtime-vapor/__tests__/vShow.spec.ts

@@ -29,7 +29,7 @@ const createDemo = (defaultValue: boolean) =>
         1: [n2],
       } = children(n0)
       withDirectives(n2, [[vShow, () => visible.value]])
-      on(n1 as HTMLElement, 'click', handleClick)
+      on(n1 as HTMLElement, 'click', () => handleClick)
       return n0
     },
   })

+ 7 - 7
packages/runtime-vapor/src/directives/vModel.ts

@@ -8,7 +8,7 @@ import {
 } from '@vue/shared'
 import type { ComponentInternalInstance } from '../component'
 import type { ObjectDirective } from '../directive'
-import { on } from '../dom/on'
+import { addEventListener } from '../dom/event'
 import { nextTick } from '../scheduler'
 import { warn } from '../warning'
 
@@ -50,7 +50,7 @@ export const vModelText: ObjectDirective<
     assignFnMap.set(el, assigner)
 
     const castToNumber = number // || (vnode.props && vnode.props.type === 'number')
-    on(el, lazy ? 'change' : 'input', e => {
+    addEventListener(el, lazy ? 'change' : 'input', e => {
       if ((e.target as any).composing) return
       let domValue: string | number = el.value
       if (trim) {
@@ -62,18 +62,18 @@ export const vModelText: ObjectDirective<
       assigner(domValue)
     })
     if (trim) {
-      on(el, 'change', () => {
+      addEventListener(el, 'change', () => {
         el.value = el.value.trim()
       })
     }
     if (!lazy) {
-      on(el, 'compositionstart', onCompositionStart)
-      on(el, 'compositionend', onCompositionEnd)
+      addEventListener(el, 'compositionstart', onCompositionStart)
+      addEventListener(el, 'compositionend', onCompositionEnd)
       // Safari < 10.2 & UIWebView doesn't fire compositionend when
       // switching focus before confirming composition choice
       // this also fixes the issue where some browsers e.g. iOS Chrome
       // fires "change" instead of "input" on autocomplete.
-      on(el, 'change', onCompositionEnd)
+      addEventListener(el, 'change', onCompositionEnd)
     }
   },
   // set value on mounted so it's after min/max for type="range"
@@ -122,7 +122,7 @@ export const vModelSelect: ObjectDirective<HTMLSelectElement, any, 'number'> = {
     { value, oldValue, instance, modifiers: { number = false } = {} },
   ) {
     const isSetModel = isSet(value)
-    on(el, 'change', () => {
+    addEventListener(el, 'change', () => {
       const selectedVal = Array.prototype.filter
         .call(el.options, (o: HTMLOptionElement) => o.selected)
         .map((o: HTMLOptionElement) =>

+ 2 - 2
packages/runtime-vapor/src/dom.ts

@@ -1,9 +1,9 @@
 import { isArray, toDisplayString } from '@vue/shared'
 import type { Block, ParentBlock } from './render'
 
-export * from './dom/patchProp'
+export * from './dom/prop'
+export * from './dom/event'
 export * from './dom/templateRef'
-export * from './dom/on'
 
 export function normalizeBlock(block: Block): Node[] {
   const nodes: Node[] = []

+ 55 - 0
packages/runtime-vapor/src/dom/event.ts

@@ -0,0 +1,55 @@
+import {
+  getCurrentEffect,
+  getCurrentScope,
+  onEffectCleanup,
+  onScopeDispose,
+} from '@vue/reactivity'
+import { recordPropMetadata } from './prop'
+import { toHandlerKey } from '@vue/shared'
+import { withKeys, withModifiers } from '@vue/runtime-dom'
+
+export function addEventListener(
+  el: HTMLElement,
+  event: string,
+  handler: (...args: any) => any,
+  options?: AddEventListenerOptions,
+) {
+  el.addEventListener(event, handler, options)
+  return () => el.removeEventListener(event, handler, options)
+}
+
+export function on(
+  el: HTMLElement,
+  event: string,
+  handlerGetter: () => undefined | ((...args: any[]) => any),
+  options?: AddEventListenerOptions,
+  { modifiers, keys }: { modifiers?: string[]; keys?: string[] } = {},
+) {
+  recordPropMetadata(el, toHandlerKey(event), handlerGetter)
+  const cleanup = addEventListener(
+    el,
+    event,
+    (...args: any[]) => {
+      let handler = handlerGetter()
+      if (!handler) return
+
+      if (modifiers) {
+        handler = withModifiers(handler, modifiers)
+      }
+      if (keys) {
+        handler = withKeys(handler, keys)
+      }
+      handler && handler(...args)
+    },
+    options,
+  )
+
+  const scope = getCurrentScope()
+  const effect = getCurrentEffect()
+
+  if (effect && effect.scope === scope) {
+    onEffectCleanup(cleanup)
+  } else if (scope) {
+    onScopeDispose(cleanup)
+  }
+}

+ 0 - 28
packages/runtime-vapor/src/dom/on.ts

@@ -1,28 +0,0 @@
-import {
-  getCurrentEffect,
-  getCurrentScope,
-  onEffectCleanup,
-  onScopeDispose,
-} from '@vue/reactivity'
-import { recordPropMetadata } from './patchProp'
-import { toHandlerKey } from '@vue/shared'
-
-export function on(
-  el: HTMLElement,
-  event: string,
-  handler: (...args: any) => any,
-  options?: AddEventListenerOptions,
-) {
-  recordPropMetadata(el, toHandlerKey(event), handler)
-  el.addEventListener(event, handler, options)
-
-  const scope = getCurrentScope()
-  const effect = getCurrentEffect()
-
-  const cleanup = () => el.removeEventListener(event, handler, options)
-  if (effect && effect.scope === scope) {
-    onEffectCleanup(cleanup)
-  } else if (scope) {
-    onScopeDispose(cleanup)
-  }
-}

+ 0 - 0
packages/runtime-vapor/src/dom/patchProp.ts → packages/runtime-vapor/src/dom/prop.ts


+ 0 - 1
packages/runtime-vapor/src/index.ts

@@ -37,7 +37,6 @@ export {
   getCurrentScope,
   onScopeDispose,
 } from '@vue/reactivity'
-export { withModifiers, withKeys } from '@vue/runtime-dom'
 
 export { nextTick } from './scheduler'
 export { getCurrentInstance, type ComponentInternalInstance } from './component'