vOn.ts 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139
  1. import {
  2. transformOn as baseTransform,
  3. DirectiveTransform,
  4. createObjectProperty,
  5. createCallExpression,
  6. createSimpleExpression,
  7. NodeTypes,
  8. createCompoundExpression,
  9. ExpressionNode,
  10. SimpleExpressionNode,
  11. isStaticExp
  12. } from '@vue/compiler-core'
  13. import { V_ON_WITH_MODIFIERS, V_ON_WITH_KEYS } from '../runtimeHelpers'
  14. import { makeMap, capitalize } from '@vue/shared'
  15. const isEventOptionModifier = /*#__PURE__*/ makeMap(`passive,once,capture`)
  16. const isNonKeyModifier = /*#__PURE__*/ makeMap(
  17. // event propagation management
  18. `stop,prevent,self,` +
  19. // system modifiers + exact
  20. `ctrl,shift,alt,meta,exact,` +
  21. // mouse
  22. `middle`
  23. )
  24. // left & right could be mouse or key modifiers based on event type
  25. const maybeKeyModifier = /*#__PURE__*/ makeMap('left,right')
  26. const isKeyboardEvent = /*#__PURE__*/ makeMap(
  27. `onkeyup,onkeydown,onkeypress`,
  28. true
  29. )
  30. const resolveModifiers = (key: ExpressionNode, modifiers: string[]) => {
  31. const keyModifiers = []
  32. const nonKeyModifiers = []
  33. const eventOptionModifiers = []
  34. for (let i = 0; i < modifiers.length; i++) {
  35. const modifier = modifiers[i]
  36. if (isEventOptionModifier(modifier)) {
  37. // eventOptionModifiers: modifiers for addEventListener() options,
  38. // e.g. .passive & .capture
  39. eventOptionModifiers.push(modifier)
  40. } else {
  41. // runtimeModifiers: modifiers that needs runtime guards
  42. if (maybeKeyModifier(modifier)) {
  43. if (isStaticExp(key)) {
  44. if (isKeyboardEvent((key as SimpleExpressionNode).content)) {
  45. keyModifiers.push(modifier)
  46. } else {
  47. nonKeyModifiers.push(modifier)
  48. }
  49. } else {
  50. keyModifiers.push(modifier)
  51. nonKeyModifiers.push(modifier)
  52. }
  53. } else {
  54. if (isNonKeyModifier(modifier)) {
  55. nonKeyModifiers.push(modifier)
  56. } else {
  57. keyModifiers.push(modifier)
  58. }
  59. }
  60. }
  61. }
  62. return {
  63. keyModifiers,
  64. nonKeyModifiers,
  65. eventOptionModifiers
  66. }
  67. }
  68. const transformClick = (key: ExpressionNode, event: string) => {
  69. const isStaticClick =
  70. isStaticExp(key) && key.content.toLowerCase() === 'onclick'
  71. return isStaticClick
  72. ? createSimpleExpression(event, true)
  73. : key.type !== NodeTypes.SIMPLE_EXPRESSION
  74. ? createCompoundExpression([
  75. `(`,
  76. key,
  77. `) === "onClick" ? "${event}" : (`,
  78. key,
  79. `)`
  80. ])
  81. : key
  82. }
  83. export const transformOn: DirectiveTransform = (dir, node, context) => {
  84. return baseTransform(dir, node, context, baseResult => {
  85. const { modifiers } = dir
  86. if (!modifiers.length) return baseResult
  87. let { key, value: handlerExp } = baseResult.props[0]
  88. const {
  89. keyModifiers,
  90. nonKeyModifiers,
  91. eventOptionModifiers
  92. } = resolveModifiers(key, modifiers)
  93. // normalize click.right and click.middle since they don't actually fire
  94. if (nonKeyModifiers.includes('right')) {
  95. key = transformClick(key, `onContextmenu`)
  96. }
  97. if (nonKeyModifiers.includes('middle')) {
  98. key = transformClick(key, `onMouseup`)
  99. }
  100. if (nonKeyModifiers.length) {
  101. handlerExp = createCallExpression(context.helper(V_ON_WITH_MODIFIERS), [
  102. handlerExp,
  103. JSON.stringify(nonKeyModifiers)
  104. ])
  105. }
  106. if (
  107. keyModifiers.length &&
  108. // if event name is dynamic, always wrap with keys guard
  109. (!isStaticExp(key) || isKeyboardEvent(key.content))
  110. ) {
  111. handlerExp = createCallExpression(context.helper(V_ON_WITH_KEYS), [
  112. handlerExp,
  113. JSON.stringify(keyModifiers)
  114. ])
  115. }
  116. if (eventOptionModifiers.length) {
  117. const modifierPostfix = eventOptionModifiers.map(capitalize).join('')
  118. key = isStaticExp(key)
  119. ? createSimpleExpression(`${key.content}${modifierPostfix}`, true)
  120. : createCompoundExpression([`(`, key, `) + "${modifierPostfix}"`])
  121. }
  122. return {
  123. props: [createObjectProperty(key, handlerExp)]
  124. }
  125. })
  126. }