model.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495
  1. import { addHandler, addProp, getBindingAttr } from '../../../../compiler/helpers'
  2. export default function model (el, dir) {
  3. const value = dir.value
  4. const modifiers = dir.modifiers
  5. if (el.tag === 'select') {
  6. if (el.attrsMap.multiple != null) {
  7. genMultiSelect(el, value)
  8. } else {
  9. genSelect(el, value)
  10. }
  11. } else {
  12. switch (el.attrsMap.type) {
  13. case 'checkbox':
  14. genCheckboxModel(el, value)
  15. break
  16. case 'radio':
  17. genRadioModel(el, value)
  18. break
  19. default:
  20. return genDefaultModel(el, value, modifiers)
  21. }
  22. }
  23. }
  24. function genCheckboxModel (el, value) {
  25. const valueBinding = getBindingAttr(el, 'value')
  26. addProp(el, 'checked',
  27. `Array.isArray(${value})` +
  28. `?(${value}).indexOf(${valueBinding})>-1` +
  29. `:!!(${value})`
  30. )
  31. addHandler(el, 'change',
  32. `var $$a=${value},` +
  33. '$$el=$event.target,' +
  34. '$$c=$$el.checked;' +
  35. 'if(Array.isArray($$a)){' +
  36. `var $$v=${valueBinding},` +
  37. '$$i=$$a.indexOf($$v);' +
  38. 'if($$c){$$i<0&&$$a.push($$v)}' +
  39. 'else{$$i>-1&&$$a.splice($$i,1)}' +
  40. `}else{${value}=$$c}`
  41. )
  42. }
  43. function genRadioModel (el, value) {
  44. const valueBinding = getBindingAttr(el, 'value')
  45. addProp(el, 'checked', `(${value}==${valueBinding})`)
  46. addHandler(el, 'change', `${value}=${valueBinding}`)
  47. }
  48. function genDefaultModel (el, value, modifiers) {
  49. const type = el.attrsMap.type
  50. const { lazy, number, trim } = modifiers || {}
  51. const event = lazy ? 'change' : 'input'
  52. const needCompositionGuard = !lazy && type !== 'range'
  53. const valueExpression = `$event.target.value${trim ? '.trim()' : ''}`
  54. let code = number || type === 'number'
  55. ? `${value}=Number(${valueExpression})`
  56. : `${value}=${valueExpression}`
  57. if (needCompositionGuard) {
  58. code = `if($event.target.composing)return;${code}`
  59. }
  60. addProp(el, 'value', `(${value})`)
  61. addHandler(el, event, code)
  62. if (needCompositionGuard) {
  63. // need runtime directive code to help with composition events
  64. return true
  65. }
  66. }
  67. const getSelectedValueCode =
  68. 'Array.prototype.filter' +
  69. '.call($event.target.options,function(o){return o.selected})' +
  70. '.map(function(o){return "_value" in o ? o._value : o.value})'
  71. function patchChildOptions (el, fn) {
  72. for (let i = 0; i < el.children.length; i++) {
  73. let c = el.children[i]
  74. if (c.tag === 'option') {
  75. addProp(c, 'selected', fn(getBindingAttr(c, 'value')))
  76. }
  77. }
  78. }
  79. function genSelect (el, value) {
  80. addHandler(el, 'change', `${value}=${getSelectedValueCode}[0]`)
  81. patchChildOptions(el, valueBinding => `$(${value})===(${valueBinding})`)
  82. }
  83. function genMultiSelect (el, value) {
  84. addHandler(el, 'change', `${value}=${getSelectedValueCode}`)
  85. patchChildOptions(el, valueBinding => `$(${value}).indexOf(${valueBinding})>-1`)
  86. }