Просмотр исходного кода

support array for checkbox v-model & :value bindings for non-strings

Evan You 10 лет назад
Родитель
Сommit
6a000c3b5a
2 измененных файлов с 46 добавлено и 17 удалено
  1. 36 15
      src/compiler/codegen/directives/model.js
  2. 10 2
      src/runtime/dom/modules/props.js

+ 36 - 15
src/compiler/codegen/directives/model.js

@@ -24,13 +24,29 @@ export function model (el, dir) {
 }
 
 function genCheckboxModel (el, value) {
-  addProp(el, 'checked', `!!(${value})`)
-  addHandler(el, 'change', `${value}=$event.target.checked`)
+  const valueBinding = getBindingAttr(el, 'value')
+  addProp(el, 'checked',
+    `Array.isArray(${value})` +
+      `?(${value}).indexOf(${valueBinding})>-1` +
+      `:!!(${value})`
+  )
+  addHandler(el, 'change',
+    `var $$a=${value},` +
+        '$$el=$event.target,' +
+        '$$c=$$el.checked;' +
+    'if(Array.isArray($$a)){' +
+      `var $$v=${valueBinding},` +
+          '$$i=$$a.indexOf($$v);' +
+      'if($$c){$$i<0&&$$a.push($$v)}' +
+      'else{$$i>-1&&$$a.splice($$i,1)}' +
+    `}else{${value}=$$c}`
+  )
 }
 
 function genRadioModel (el, value) {
-  addProp(el, 'checked', `(${value}==${getBindingAttr(el, 'value')})`)
-  addHandler(el, 'change', `${value}=$event.target.value`)
+  const valueBinding = getBindingAttr(el, 'value')
+  addProp(el, 'checked', `(${value}==${valueBinding})`)
+  addHandler(el, 'change', `${value}=${valueBinding}`)
 }
 
 function genDefaultModel (el, value, modifiers) {
@@ -54,21 +70,26 @@ function genDefaultModel (el, value, modifiers) {
   }
 }
 
-function genSelect (el, value) {
-  addProp(el, 'value', `(${value})`)
-  addHandler(el, 'change', `${value}=$event.target.value`)
-}
+const getSelectedValueCode =
+  'Array.prototype.filter' +
+  '.call($event.target.options,function(o){return o.selected})' +
+  '.map(function(o){return "_value" in o ? o._value : o.value})'
 
-function genMultiSelect (el, value) {
-  addHandler(el, 'change',
-    `${value}=Array.prototype.filter
-    .call($event.target.options,function(o){return o.selected})
-    .map(function(o){return o.value})`)
-  // patch child options
+function patchChildOptions (el, fn) {
   for (let i = 0; i < el.children.length; i++) {
     let c = el.children[i]
     if (c.tag === 'option') {
-      addProp(c, 'selected', `(${value}).indexOf(${getBindingAttr(c, 'value')})>-1`)
+      addProp(c, 'selected', fn(getBindingAttr(c, 'value')))
     }
   }
 }
+
+function genSelect (el, value) {
+  addHandler(el, 'change', `${value}=${getSelectedValueCode}[0]`)
+  patchChildOptions(el, valueBinding => `$(${value})===(${valueBinding})`)
+}
+
+function genMultiSelect (el, value) {
+  addHandler(el, 'change', `${value}=${getSelectedValueCode}`)
+  patchChildOptions(el, valueBinding => `$(${value}).indexOf(${valueBinding})>-1`)
+}

+ 10 - 2
src/runtime/dom/modules/props.js

@@ -15,8 +15,16 @@ function updateProps (oldVnode, vnode) {
   for (key in props) {
     cur = props[key]
     old = oldProps[key]
-    if (old !== cur && (key !== 'value' || elm[key] !== cur)) {
-      elm[key] = cur
+    if (old !== cur) {
+      if (key === 'value') {
+        // store value as _value as well since
+        // non-string values will be stringified
+        if (elm._value !== cur) {
+          elm.value = elm._value = cur
+        }
+      } else {
+        elm[key] = cur
+      }
     }
   }
 }