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

fix(v-model): avoid unnecessary change event on select options change

fix #6193
via #6194
JK 8 лет назад
Родитель
Сommit
d4d553ced7

+ 12 - 1
src/platforms/web/runtime/directives/model.js

@@ -53,7 +53,14 @@ export default {
       const prevOptions = el._vOptions
       const curOptions = el._vOptions = [].map.call(el.options, getValue)
       if (curOptions.some((o, i) => !looseEqual(o, prevOptions[i]))) {
-        trigger(el, 'change')
+        // trigger change event if
+        // no matching option found for at least one value
+        const needReset = el.multiple
+          ? binding.value.some(v => hasNoMatchingOption(v, curOptions))
+          : binding.value !== binding.oldValue && hasNoMatchingOption(binding.value, curOptions)
+        if (needReset) {
+          trigger(el, 'change')
+        }
       }
     }
   }
@@ -104,6 +111,10 @@ function actuallySetSelected (el, binding, vm) {
   }
 }
 
+function hasNoMatchingOption (value, options) {
+  return options.every(o => !looseEqual(o, value))
+}
+
 function getValue (option) {
   return '_value' in option
     ? option._value

+ 29 - 0
test/unit/features/directives/model-select.spec.js

@@ -517,4 +517,33 @@ describe('Directive v-model select', () => {
       expect(vm.test).toBe('2')
     }).then(done)
   })
+
+  // #6193
+  it('should not trigger change event when matching option can be found for each value', done => {
+    const spy = jasmine.createSpy()
+    const vm = new Vue({
+      data: {
+        options: ['1']
+      },
+      computed: {
+        test: {
+          get () {
+            return '1'
+          },
+          set () {
+            spy()
+          }
+        }
+      },
+      template:
+        '<select v-model="test">' +
+          '<option :key="opt" v-for="opt in options" :value="opt">{{ opt }}</option>' +
+        '</select>'
+    }).$mount()
+
+    vm.options = ['1', '2']
+    waitForUpdate(() => {
+      expect(spy).not.toHaveBeenCalled()
+    }).then(done)
+  })
 })