events.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150
  1. /* @flow */
  2. const fnExpRE = /^([\w$_]+|\([^)]*?\))\s*=>|^function\s*\(/
  3. const simplePathRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\['[^']*?']|\["[^"]*?"]|\[\d+]|\[[A-Za-z_$][\w$]*])*$/
  4. // keyCode aliases
  5. const keyCodes: { [key: string]: number | Array<number> } = {
  6. esc: 27,
  7. tab: 9,
  8. enter: 13,
  9. space: 32,
  10. up: 38,
  11. left: 37,
  12. right: 39,
  13. down: 40,
  14. 'delete': [8, 46]
  15. }
  16. // #4868: modifiers that prevent the execution of the listener
  17. // need to explicitly return null so that we can determine whether to remove
  18. // the listener for .once
  19. const genGuard = condition => `if(${condition})return null;`
  20. const modifierCode: { [key: string]: string } = {
  21. stop: '$event.stopPropagation();',
  22. prevent: '$event.preventDefault();',
  23. self: genGuard(`$event.target !== $event.currentTarget`),
  24. ctrl: genGuard(`!$event.ctrlKey`),
  25. shift: genGuard(`!$event.shiftKey`),
  26. alt: genGuard(`!$event.altKey`),
  27. meta: genGuard(`!$event.metaKey`),
  28. left: genGuard(`'button' in $event && $event.button !== 0`),
  29. middle: genGuard(`'button' in $event && $event.button !== 1`),
  30. right: genGuard(`'button' in $event && $event.button !== 2`)
  31. }
  32. export function genHandlers (
  33. events: ASTElementHandlers,
  34. isNative: boolean,
  35. warn: Function
  36. ): string {
  37. let res = isNative ? 'nativeOn:{' : 'on:{'
  38. for (const name in events) {
  39. res += `"${name}":${genHandler(name, events[name])},`
  40. }
  41. return res.slice(0, -1) + '}'
  42. }
  43. // Generate handler code with binding params on Weex
  44. /* istanbul ignore next */
  45. function genWeexHandler (params: Array<any>, handlerCode: string) {
  46. let innerHandlerCode = handlerCode
  47. const exps = params.filter(exp => simplePathRE.test(exp) && exp !== '$event')
  48. const bindings = exps.map(exp => ({ '@binding': exp }))
  49. const args = exps.map((exp, i) => {
  50. const key = `$_${i + 1}`
  51. innerHandlerCode = innerHandlerCode.replace(exp, key)
  52. return key
  53. })
  54. args.push('$event')
  55. return '{\n' +
  56. `handler:function(${args.join(',')}){${innerHandlerCode}},\n` +
  57. `params:${JSON.stringify(bindings)}\n` +
  58. '}'
  59. }
  60. function genHandler (
  61. name: string,
  62. handler: ASTElementHandler | Array<ASTElementHandler>
  63. ): string {
  64. if (!handler) {
  65. return 'function(){}'
  66. }
  67. if (Array.isArray(handler)) {
  68. return `[${handler.map(handler => genHandler(name, handler)).join(',')}]`
  69. }
  70. const isMethodPath = simplePathRE.test(handler.value)
  71. const isFunctionExpression = fnExpRE.test(handler.value)
  72. if (!handler.modifiers) {
  73. if (isMethodPath || isFunctionExpression) {
  74. return handler.value
  75. }
  76. /* istanbul ignore if */
  77. if (__WEEX__ && handler.params) {
  78. return genWeexHandler(handler.params, handler.value)
  79. }
  80. return `function($event){${handler.value}}` // inline statement
  81. } else {
  82. let code = ''
  83. let genModifierCode = ''
  84. const keys = []
  85. for (const key in handler.modifiers) {
  86. if (modifierCode[key]) {
  87. genModifierCode += modifierCode[key]
  88. // left/right
  89. if (keyCodes[key]) {
  90. keys.push(key)
  91. }
  92. } else if (key === 'exact') {
  93. const modifiers: ASTModifiers = (handler.modifiers: any)
  94. genModifierCode += genGuard(
  95. ['ctrl', 'shift', 'alt', 'meta']
  96. .filter(keyModifier => !modifiers[keyModifier])
  97. .map(keyModifier => `$event.${keyModifier}Key`)
  98. .join('||')
  99. )
  100. } else {
  101. keys.push(key)
  102. }
  103. }
  104. if (keys.length) {
  105. code += genKeyFilter(keys)
  106. }
  107. // Make sure modifiers like prevent and stop get executed after key filtering
  108. if (genModifierCode) {
  109. code += genModifierCode
  110. }
  111. const handlerCode = isMethodPath
  112. ? handler.value + '($event)'
  113. : isFunctionExpression
  114. ? `(${handler.value})($event)`
  115. : handler.value
  116. /* istanbul ignore if */
  117. if (__WEEX__ && handler.params) {
  118. return genWeexHandler(handler.params, code + handlerCode)
  119. }
  120. return `function($event){${code}${handlerCode}}`
  121. }
  122. }
  123. function genKeyFilter (keys: Array<string>): string {
  124. return `if(!('button' in $event)&&${keys.map(genFilterCode).join('&&')})return null;`
  125. }
  126. function genFilterCode (key: string): string {
  127. const keyVal = parseInt(key, 10)
  128. if (keyVal) {
  129. return `$event.keyCode!==${keyVal}`
  130. }
  131. const code = keyCodes[key]
  132. return (
  133. `_k($event.keyCode,` +
  134. `${JSON.stringify(key)},` +
  135. `${JSON.stringify(code)},` +
  136. `$event.key)`
  137. )
  138. }