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

avoid v-model with .trim/.number updating value when in focus (fix #4392)

Evan You 9 лет назад
Родитель
Сommit
8a7b02a159

+ 6 - 0
src/platforms/web/compiler/directives/model.js

@@ -127,10 +127,12 @@ function genDefaultModel (
   valueExpression = number || type === 'number'
     ? `_n(${valueExpression})`
     : valueExpression
+
   let code = genAssignmentCode(value, valueExpression)
   if (isNative && needCompositionGuard) {
     code = `if($event.target.composing)return;${code}`
   }
+
   // inputs with type="file" are read only and setting the input's
   // value will throw an error.
   if (process.env.NODE_ENV !== 'production' &&
@@ -140,8 +142,12 @@ function genDefaultModel (
       `File inputs are read only. Use a v-on:change listener instead.`
     )
   }
+
   addProp(el, 'value', isNative ? `_s(${value})` : `(${value})`)
   addHandler(el, event, code, null, true)
+  if (trim || number || type === 'number') {
+    addHandler(el, 'blur', '$forceUpdate()')
+  }
 }
 
 function genSelect (

+ 1 - 1
src/platforms/web/runtime/modules/dom-props.js

@@ -35,7 +35,7 @@ function updateDOMProps (oldVnode: VNodeWithData, vnode: VNodeWithData) {
       elm._value = cur
       // avoid resetting cursor position when value is the same
       const strCur = cur == null ? '' : String(cur)
-      if (elm.value !== strCur && !elm.composing) {
+      if (elm.value !== strCur && !elm.composing && document.activeElement !== elm) {
         elm.value = strCur
       }
     } else {

+ 55 - 0
test/unit/features/directives/model-text.spec.js

@@ -64,6 +64,61 @@ describe('Directive v-model text', () => {
     expect(vm.test).toBe('what')
   })
 
+  it('.number focus and typing', (done) => {
+    const vm = new Vue({
+      data: {
+        test: 0,
+        update: 0
+      },
+      template:
+        '<div>' +
+          '<input ref="input" v-model="test" type="number">{{ update }}' +
+          '<input ref="blur"/>' +
+        '</div>'
+    }).$mount()
+    document.body.appendChild(vm.$el)
+    vm.$refs.input.focus()
+    expect(vm.test).toBe(0)
+    vm.$refs.input.value = '1.0'
+    triggerEvent(vm.$refs.input, 'input')
+    expect(vm.test).toBe(1)
+    vm.update++
+    waitForUpdate(() => {
+      expect(vm.$refs.input.value).toBe('1.0')
+      vm.$refs.blur.focus()
+      vm.update++
+    }).then(() => {
+      expect(vm.$refs.input.value).toBe('1')
+    }).then(done)
+  })
+
+  it('.trim focus and typing', (done) => {
+    const vm = new Vue({
+      data: {
+        test: 'abc',
+        update: 0
+      },
+      template:
+        '<div>' +
+          '<input ref="input" v-model.trim="test" type="text">{{ update }}' +
+          '<input ref="blur"/>' +
+        '</div>'
+    }).$mount()
+    document.body.appendChild(vm.$el)
+    vm.$refs.input.focus()
+    vm.$refs.input.value = ' abc '
+    triggerEvent(vm.$refs.input, 'input')
+    expect(vm.test).toBe('abc')
+    vm.update++
+    waitForUpdate(() => {
+      expect(vm.$refs.input.value).toBe(' abc ')
+      vm.$refs.blur.focus()
+      vm.update++
+    }).then(() => {
+      expect(vm.$refs.input.value).toBe('abc')
+    }).then(done)
+  })
+
   it('multiple inputs', (done) => {
     const spy = jasmine.createSpy()
     const vm = new Vue({