Browse Source

fix(vdom): Don't replace input for text-like type change (#6344)

fix #6313
dev
Nick Messing 7 years ago
committed by Evan You
parent
commit
f76d16ed95
  1. 7
      src/core/vdom/patch.js
  2. 5
      src/platforms/web/runtime/directives/model.js
  3. 2
      src/platforms/web/util/element.js
  4. 26
      test/unit/modules/vdom/patch/edge-cases.spec.js

7
src/core/vdom/patch.js

@ -6,8 +6,6 @@
*
* modified by Evan You (@yyx990803)
*
/*
* Not type-checking this because this file is perf-critical and the cost
* of making flow understand it is not worth it.
*/
@ -17,6 +15,7 @@ import config from '../config'
import { SSR_ATTR } from 'shared/constants'
import { registerRef } from './modules/ref'
import { activeInstance } from '../instance/lifecycle'
import { isTextInputType } from 'web/util/element'
import {
warn,
@ -48,14 +47,12 @@ function sameVnode (a, b) {
)
}
// Some browsers do not support dynamically changing type for <input>
// so they need to be treated as different nodes
function sameInputType (a, b) {
if (a.tag !== 'input') return true
let i
const typeA = isDef(i = a.data) && isDef(i = i.attrs) && i.type
const typeB = isDef(i = b.data) && isDef(i = i.attrs) && i.type
return typeA === typeB
return typeA === typeB || isTextInputType(typeA) && isTextInputType(typeB)
}
function createKeyToOldIdx (children, beginIdx, endIdx) {

5
src/platforms/web/runtime/directives/model.js

@ -3,11 +3,10 @@
* properties to Elements.
*/
import { looseEqual, looseIndexOf, makeMap } from 'shared/util'
import { isTextInputType } from 'web/util/element'
import { looseEqual, looseIndexOf } from 'shared/util'
import { warn, isAndroid, isIE9, isIE, isEdge } from 'core/util/index'
const isTextInputType = makeMap('text,number,password,search,email,tel,url')
/* istanbul ignore if */
if (isIE9) {
// http://www.matts411.com/post/internet-explorer-9-oninput/

2
src/platforms/web/util/element.js

@ -73,3 +73,5 @@ export function isUnknownElement (tag: string): boolean {
return (unknownElementCache[tag] = /HTMLUnknownElement/.test(el.toString()))
}
}
export const isTextInputType = makeMap('text,number,password,search,email,tel,url')

26
test/unit/modules/vdom/patch/edge-cases.spec.js

@ -135,4 +135,30 @@ describe('vdom patch: edge cases', () => {
expect(vm.$el.children[0].value).toBe('a')
}).then(done)
})
// #6313
it('should not replace node when switching between text-like inputs', done => {
const vm = new Vue({
data: { show: false },
template: `
<div>
<input :type="show ? 'text' : 'password'">
</div>
`
}).$mount()
const node = vm.$el.children[0]
expect(vm.$el.children[0].type).toBe('password')
vm.$el.children[0].value = 'test'
vm.show = true
waitForUpdate(() => {
expect(vm.$el.children[0]).toBe(node)
expect(vm.$el.children[0].value).toBe('test')
expect(vm.$el.children[0].type).toBe('text')
vm.show = false
}).then(() => {
expect(vm.$el.children[0]).toBe(node)
expect(vm.$el.children[0].value).toBe('test')
expect(vm.$el.children[0].type).toBe('password')
}).then(done)
})
})

Loading…
Cancel
Save