]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
feat(compiler): v-on event modifier (#8)
authorubugeeei <71201308+Ubugeeei@users.noreply.github.com>
Wed, 29 Nov 2023 21:11:59 +0000 (06:11 +0900)
committerGitHub <noreply@github.com>
Wed, 29 Nov 2023 21:11:59 +0000 (05:11 +0800)
packages/compiler-vapor/__tests__/__snapshots__/compile.test.ts.snap
packages/compiler-vapor/__tests__/compile.test.ts
packages/compiler-vapor/src/generate.ts
packages/compiler-vapor/src/ir.ts
packages/compiler-vapor/src/transform.ts
packages/runtime-vapor/src/index.ts
playground/src/event-modifier.vue [new file with mode: 0644]

index 92181bc6e0d607689756a0c47b776220714825de..4f9dbf8d29c123e743cbeda1e5d9060389f88781 100644 (file)
@@ -71,6 +71,22 @@ export function render() {
 "
 `;
 
+exports[`compile > directives > v-on > event modifier 1`] = `
+"import { template, children, effect, withModifiers, on } from 'vue/vapor';
+const t0 = template('<div></div>');
+export function render() {
+  const n0 = t0();
+  const {
+    0: [n1],
+  } = children(n0);
+  effect(() => {
+    on(n1, 'click', withModifiers(handleClick, ['prevent', 'stop']));
+  });
+  return n0;
+}
+"
+`;
+
 exports[`compile > directives > v-on > simple expression 1`] = `
 "import { template, children, effect, on } from 'vue/vapor';
 const t0 = template('<div></div>');
index e9766a806003c6a853747099e8bcb77deaa71450..8fa34b5ed303997939c18d07bde0be893fe91d89 100644 (file)
@@ -120,6 +120,18 @@ describe('compile', () => {
           },
         })
       })
+
+      test('event modifier', async () => {
+        const code = await compile(
+          `<div @click.prevent.stop="handleClick"></div>`,
+          {
+            bindingMetadata: {
+              handleClick: BindingTypes.SETUP_CONST,
+            },
+          },
+        )
+        expect(code).matchSnapshot()
+      })
     })
 
     describe('v-html', () => {
index 0af9d764bc0b6b66c775d21aafaccd0271a863f5..e21f0f02bb936071cba991b09e353c551646930f 100644 (file)
@@ -98,9 +98,14 @@ export function generate(
       }
 
       case IRNodeTypes.SET_EVENT: {
-        code = `on(n${oper.element}, ${JSON.stringify(oper.name)}, ${
-          oper.value
-        })\n`
+        let value = oper.value
+        if (oper.modifiers.length) {
+          value = `withModifiers(${value}, ${genArrayExpression(
+            oper.modifiers,
+          )})`
+          vaporHelpers.add('withModifiers')
+        }
+        code = `on(n${oper.element}, ${JSON.stringify(oper.name)}, ${value})\n`
         vaporHelpers.add('on')
         break
       }
@@ -172,3 +177,8 @@ function genChildren(children: DynamicChildren) {
   if (!code) return ''
   return `{${code}}`
 }
+
+// TODO: other types (not only string)
+function genArrayExpression(elements: string[]) {
+  return `[${elements.map((it) => `"${it}"`).join(', ')}]`
+}
index b3892a3cdd0f3b462beb89177d70023bc337bbba..31deb1e4dda2e79b8588a350791ce4e2c29e7da5 100644 (file)
@@ -59,6 +59,7 @@ export interface SetEventIRNode extends IRNode {
   element: number
   name: string
   value: string
+  modifiers: string[]
 }
 
 export interface SetHtmlIRNode extends IRNode {
index d7f5b7f1ad21d700453b8b17edda77f98b0ce0d4..d304c28963359b30b16f9afb2249f0e934f431bc 100644 (file)
@@ -416,6 +416,7 @@ function transformProp(
         element: ctx.reference(),
         name: node.arg.content,
         value: expr,
+        modifiers,
       })
       break
     }
index 9e47af592c5e629544ea1f894acd383c2da23d19..0eebcbbf8bdb32425e8d4c0f8a856fe12ca74972 100644 (file)
@@ -39,3 +39,5 @@ export { effect } from './scheduler'
 export * from './on'
 export * from './render'
 export * from './template'
+export * from './scheduler'
+export { withModifiers } from '@vue/runtime-dom'
diff --git a/playground/src/event-modifier.vue b/playground/src/event-modifier.vue
new file mode 100644 (file)
index 0000000..97e6fe3
--- /dev/null
@@ -0,0 +1,18 @@
+<script setup lang="ts">
+const handleClick = () => {
+  console.log('Hello, Vapor!')
+}
+
+// @ts-expect-error
+globalThis.handleClick = handleClick
+</script>
+
+<template>
+  <form>
+    <button @click="handleClick">submit</button>
+  </form>
+
+  <form>
+    <button @click.prevent="handleClick">no submit</button>
+  </form>
+</template>