From f76d16ed9507d4c2a90243ea3d77ccf00df29346 Mon Sep 17 00:00:00 2001 From: Nick Messing Date: Sat, 2 Sep 2017 10:49:39 +1200 Subject: [PATCH] fix(vdom): Don't replace input for text-like type change (#6344) fix #6313 --- src/core/vdom/patch.js | 7 ++--- src/platforms/web/runtime/directives/model.js | 5 ++-- src/platforms/web/util/element.js | 2 ++ .../modules/vdom/patch/edge-cases.spec.js | 26 +++++++++++++++++++ 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/src/core/vdom/patch.js b/src/core/vdom/patch.js index e4bec3269f..db491e88ac 100644 --- a/src/core/vdom/patch.js +++ b/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 -// 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) { diff --git a/src/platforms/web/runtime/directives/model.js b/src/platforms/web/runtime/directives/model.js index c6fac9dcca..8923981688 100644 --- a/src/platforms/web/runtime/directives/model.js +++ b/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/ diff --git a/src/platforms/web/util/element.js b/src/platforms/web/util/element.js index 1cea48d5e5..65f1aafbbf 100644 --- a/src/platforms/web/util/element.js +++ b/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') diff --git a/test/unit/modules/vdom/patch/edge-cases.spec.js b/test/unit/modules/vdom/patch/edge-cases.spec.js index 1434ee46c6..f80a741f55 100644 --- a/test/unit/modules/vdom/patch/edge-cases.spec.js +++ b/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: ` +
+ +
+ ` + }).$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) + }) })