]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
refactor(v-on): avoid empty modifier guard with only key modifier
authorEvan You <yyx990803@gmail.com>
Fri, 18 Oct 2019 20:20:45 +0000 (16:20 -0400)
committerEvan You <yyx990803@gmail.com>
Fri, 18 Oct 2019 20:20:45 +0000 (16:20 -0400)
packages/compiler-core/src/ast.ts
packages/compiler-dom/__tests__/transforms/vOn.spec.ts
packages/compiler-dom/src/runtimeHelpers.ts
packages/compiler-dom/src/transforms/vOn.ts
packages/runtime-dom/__tests__/directives/vOn.spec.ts
packages/runtime-dom/src/directives/vOn.ts
packages/runtime-dom/src/index.ts

index b2e127c0e27aeea8937a1966fddf99f86634b3a7..9825b91668c0c9a08b43020057c7fa16b664ebda 100644 (file)
@@ -190,7 +190,6 @@ export interface InterpolationNode extends Node {
   content: ExpressionNode
 }
 
-// always dynamic
 export interface CompoundExpressionNode extends Node {
   type: NodeTypes.COMPOUND_EXPRESSION
   children: (
index ac8bec7802faaf02f36774094e7c2dba8e4fbf82..a61f0c1ecc4235e964b66b9be86ff7a22257b9a2 100644 (file)
@@ -103,4 +103,17 @@ describe('compiler-dom: transform v-on', () => {
       }
     })
   })
+
+  it('should not wrap normal guard if there is only keys guard', () => {
+    const [prop] = parseVOnProperties(`<div @keyup.enter="test"/>`, {
+      prefixIdentifiers: true
+    })
+    expect(prop).toMatchObject({
+      type: NodeTypes.JS_PROPERTY,
+      value: {
+        callee: V_ON_KEYS_GUARD,
+        arguments: [{ content: '_ctx.test' }, '["enter"]']
+      }
+    })
+  })
 })
index c1405498cd0a609ab18f3ed554f4af41a9908e92..382403c03aa2c7e4e18039c082d717483ec18e85 100644 (file)
@@ -15,6 +15,6 @@ registerRuntimeHelpers({
   [V_MODEL_TEXT]: `vModelText`,
   [V_MODEL_SELECT]: `vModelSelect`,
   [V_MODEL_DYNAMIC]: `vModelDynamic`,
-  [V_ON_MODIFIERS_GUARD]: `vOnModifiersGuard`,
-  [V_ON_KEYS_GUARD]: `vOnKeysGuard`
+  [V_ON_MODIFIERS_GUARD]: `withModifiers`,
+  [V_ON_KEYS_GUARD]: `withKeys`
 })
index b817611d0e2ef02d61f6c0817c09135cd054f8c0..7df8fdbb688ae89d1b4dd734e95dc121f37cf7dc 100644 (file)
@@ -5,9 +5,7 @@ import {
   createCallExpression,
   createObjectExpression,
   createSimpleExpression,
-  NodeTypes,
-  CallExpression,
-  ObjectExpression
+  NodeTypes
 } from '@vue/compiler-core'
 import { V_ON_MODIFIERS_GUARD, V_ON_KEYS_GUARD } from '../runtimeHelpers'
 import { makeMap } from '@vue/shared'
@@ -31,12 +29,22 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
   const baseResult = baseTransform(dir, node, context)
   if (!modifiers.length) return baseResult
 
-  const { key, value } = baseResult.props[0]
+  let { key, value: handlerExp } = baseResult.props[0]
+
+  // modifiers for addEventListener() options, e.g. .passive & .capture
+  const eventOptionModifiers = modifiers.filter(isEventOptionModifier)
+  // modifiers that needs runtime guards
   const runtimeModifiers = modifiers.filter(m => !isEventOptionModifier(m))
-  let handler = createCallExpression(context.helper(V_ON_MODIFIERS_GUARD), [
-    value,
-    JSON.stringify(runtimeModifiers.filter(isNonKeyModifier))
-  ])
+
+  // built-in modifiers that are not keys
+  const nonKeyModifiers = runtimeModifiers.filter(isNonKeyModifier)
+  if (nonKeyModifiers.length) {
+    handlerExp = createCallExpression(context.helper(V_ON_MODIFIERS_GUARD), [
+      handlerExp,
+      JSON.stringify(nonKeyModifiers)
+    ])
+  }
+
   const keyModifiers = runtimeModifiers.filter(m => !isNonKeyModifier(m))
   if (
     keyModifiers.length &&
@@ -45,18 +53,15 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
       !key.isStatic ||
       isKeyboardEvent(key.content))
   ) {
-    handler = createCallExpression(context.helper(V_ON_KEYS_GUARD), [
-      handler,
+    handlerExp = createCallExpression(context.helper(V_ON_KEYS_GUARD), [
+      handlerExp,
       JSON.stringify(keyModifiers)
     ])
   }
 
-  let returnExp: CallExpression | ObjectExpression = handler
-
-  const eventOptionModifiers = modifiers.filter(isEventOptionModifier)
   if (eventOptionModifiers.length) {
-    returnExp = createObjectExpression([
-      createObjectProperty('handler', handler),
+    handlerExp = createObjectExpression([
+      createObjectProperty('handler', handlerExp),
       createObjectProperty(
         'options',
         createObjectExpression(
@@ -74,7 +79,7 @@ export const transformOn: DirectiveTransform = (dir, node, context) => {
   }
 
   return {
-    props: [createObjectProperty(key, returnExp)],
+    props: [createObjectProperty(key, handlerExp)],
     needRuntime: false
   }
 }
index 21e539fc084c339bed24bcebbb6c820c4fb2a88a..fda9d6c030d334649e433b17b23cd05584e820d7 100644 (file)
@@ -1,5 +1,5 @@
 import { patchEvent } from '../../src/modules/events'
-import { vOnModifiersGuard, vOnKeysGuard } from '@vue/runtime-dom'
+import { withModifiers, withKeys } from '@vue/runtime-dom'
 
 function triggerEvent(
   target: Element,
@@ -21,7 +21,7 @@ describe('runtime-dom: v-on directive', () => {
     const parent = document.createElement('div')
     const child = document.createElement('input')
     parent.appendChild(child)
-    const childNextValue = vOnModifiersGuard(jest.fn(), ['prevent', 'stop'])
+    const childNextValue = withModifiers(jest.fn(), ['prevent', 'stop'])
     patchEvent(child, 'click', null, childNextValue, null)
     const parentNextValue = jest.fn()
     patchEvent(parent, 'click', null, parentNextValue, null)
@@ -34,7 +34,7 @@ describe('runtime-dom: v-on directive', () => {
     const child = document.createElement('input')
     parent.appendChild(child)
     const fn = jest.fn()
-    const handler = vOnModifiersGuard(fn, ['self'])
+    const handler = withModifiers(fn, ['self'])
     patchEvent(parent, 'click', null, handler, null)
     triggerEvent(child, 'click')
     expect(fn).not.toBeCalled()
@@ -44,7 +44,7 @@ describe('runtime-dom: v-on directive', () => {
     const el = document.createElement('div')
     const fn = jest.fn()
     // <div @keyup.ctrl.esc="test"/>
-    const nextValue = vOnKeysGuard(vOnModifiersGuard(fn, ['ctrl']), ['esc'])
+    const nextValue = withKeys(withModifiers(fn, ['ctrl']), ['esc'])
     patchEvent(el, 'keyup', null, nextValue, null)
     triggerEvent(el, 'keyup', e => (e.key = 'a'))
     expect(fn).not.toBeCalled()
@@ -64,7 +64,7 @@ describe('runtime-dom: v-on directive', () => {
     const el = document.createElement('div')
     // Case 1: <div @keyup.exact="test"/>
     const fn1 = jest.fn()
-    const next1 = vOnModifiersGuard(fn1, ['exact'])
+    const next1 = withModifiers(fn1, ['exact'])
     patchEvent(el, 'keyup', null, next1, null)
     triggerEvent(el, 'keyup')
     expect(fn1.mock.calls.length).toBe(1)
@@ -72,7 +72,7 @@ describe('runtime-dom: v-on directive', () => {
     expect(fn1.mock.calls.length).toBe(1)
     // Case 2: <div @keyup.ctrl.a.exact="test"/>
     const fn2 = jest.fn()
-    const next2 = vOnKeysGuard(vOnModifiersGuard(fn2, ['ctrl', 'exact']), ['a'])
+    const next2 = withKeys(withModifiers(fn2, ['ctrl', 'exact']), ['a'])
     patchEvent(el, 'keyup', null, next2, null)
     triggerEvent(el, 'keyup', e => (e.key = 'a'))
     expect(fn2).not.toBeCalled()
@@ -96,7 +96,7 @@ describe('runtime-dom: v-on directive', () => {
     buttons.forEach(button => {
       const el = document.createElement('div')
       const fn = jest.fn()
-      const handler = vOnModifiersGuard(fn, [button])
+      const handler = withModifiers(fn, [button])
       patchEvent(el, 'mousedown', null, handler, null)
       buttons.filter(b => b !== button).forEach(button => {
         triggerEvent(el, 'mousedown', e => (e.button = buttonCodes[button]))
index 5ffbcc30596e2ca53db73aa0ae0cac279877f23d..b8b91d48197f469437d021793140028d2570d685 100644 (file)
@@ -1,6 +1,6 @@
 const systemModifiers = ['ctrl', 'shift', 'alt', 'meta']
 
-type KeyedEvent = KeyboardEvent | MouseEvent | TouchEvent;
+type KeyedEvent = KeyboardEvent | MouseEvent | TouchEvent
 
 const modifierGuards: Record<
   string,
@@ -20,7 +20,7 @@ const modifierGuards: Record<
     systemModifiers.some(m => (e as any)[`${m}Key`] && !modifiers.includes(m))
 }
 
-export const vOnModifiersGuard = (fn: Function, modifiers: string[]) => {
+export const withModifiers = (fn: Function, modifiers: string[]) => {
   return (event: Event) => {
     for (let i = 0; i < modifiers.length; i++) {
       const guard = modifierGuards[modifiers[i]]
@@ -42,7 +42,7 @@ const keyNames: Record<string, string | string[]> = {
   delete: 'backspace'
 }
 
-export const vOnKeysGuard = (fn: Function, modifiers: string[]) => {
+export const withKeys = (fn: Function, modifiers: string[]) => {
   return (event: KeyboardEvent) => {
     if (!('key' in event)) return
     const eventKey = event.key.toLowerCase()
index 35167655ea3641a0fe672a5a68c8d0327f22dc9d..a7b9e44b54d9aa045a48ea7db37399f358cf9e77 100644 (file)
@@ -31,7 +31,7 @@ export {
   vModelDynamic
 } from './directives/vModel'
 
-export { vOnModifiersGuard, vOnKeysGuard } from './directives/vOn'
+export { withModifiers, withKeys } from './directives/vOn'
 
 // re-export everything from core
 // h, Component, reactivity API, nextTick, flags & types