mirror of https://github.com/ElemeFE/element
input: fix regression (#14572)
* input: fix regression guard against: #14551 fix: #14501, #14521, #14564, #14332 * Input: updatepull/14766/head
parent
f0ae2ae759
commit
ed13de38c7
|
@ -28,11 +28,9 @@
|
|||
:disabled="inputDisabled"
|
||||
:readonly="readonly"
|
||||
:autocomplete="autoComplete || autocomplete"
|
||||
:value="nativeInputValue"
|
||||
ref="input"
|
||||
@compositionstart="handleComposition"
|
||||
@compositionupdate="handleComposition"
|
||||
@compositionend="handleComposition"
|
||||
@compositionstart="handleCompositionStart"
|
||||
@compositionend="handleCompositionEnd"
|
||||
@input="handleInput"
|
||||
@focus="handleFocus"
|
||||
@blur="handleBlur"
|
||||
|
@ -82,10 +80,8 @@
|
|||
v-else
|
||||
:tabindex="tabindex"
|
||||
class="el-textarea__inner"
|
||||
:value="nativeInputValue"
|
||||
@compositionstart="handleComposition"
|
||||
@compositionupdate="handleComposition"
|
||||
@compositionend="handleComposition"
|
||||
@compositionstart="handleCompositionStart"
|
||||
@compositionend="handleCompositionEnd"
|
||||
@input="handleInput"
|
||||
ref="textarea"
|
||||
v-bind="$attrs"
|
||||
|
@ -130,7 +126,7 @@
|
|||
textareaCalcStyle: {},
|
||||
hovering: false,
|
||||
focused: false,
|
||||
isOnComposition: false,
|
||||
isComposing: false,
|
||||
passwordVisible: false
|
||||
};
|
||||
},
|
||||
|
@ -208,7 +204,7 @@
|
|||
return this.disabled || (this.elForm || {}).disabled;
|
||||
},
|
||||
nativeInputValue() {
|
||||
return this.value === null || this.value === undefined ? '' : this.value;
|
||||
return this.value === null || this.value === undefined ? '' : String(this.value);
|
||||
},
|
||||
showClear() {
|
||||
return this.clearable &&
|
||||
|
@ -231,6 +227,12 @@
|
|||
if (this.validateEvent) {
|
||||
this.dispatch('ElFormItem', 'el.form.change', [val]);
|
||||
}
|
||||
},
|
||||
// native input value is set explicitly
|
||||
// do not use v-model / :value in template
|
||||
// see: https://github.com/ElemeFE/element/issues/14521
|
||||
nativeInputValue() {
|
||||
this.setNativeInputValue();
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -277,21 +279,27 @@
|
|||
|
||||
this.textareaCalcStyle = calcTextareaHeight(this.$refs.textarea, minRows, maxRows);
|
||||
},
|
||||
setNativeInputValue() {
|
||||
const input = this.getInput();
|
||||
if (!input) return;
|
||||
if (input.value === this.nativeInputValue) return;
|
||||
input.value = this.nativeInputValue;
|
||||
},
|
||||
handleFocus(event) {
|
||||
this.focused = true;
|
||||
this.$emit('focus', event);
|
||||
},
|
||||
handleComposition(event) {
|
||||
if (event.type === 'compositionstart') {
|
||||
this.isOnComposition = true;
|
||||
}
|
||||
if (event.type === 'compositionend') {
|
||||
this.isOnComposition = false;
|
||||
handleCompositionStart() {
|
||||
this.isComposing = true;
|
||||
},
|
||||
handleCompositionEnd(event) {
|
||||
this.isComposing = false;
|
||||
this.handleInput(event);
|
||||
}
|
||||
},
|
||||
handleInput(event) {
|
||||
if (this.isOnComposition) return;
|
||||
// should not emit input during composition
|
||||
// see: https://github.com/ElemeFE/element/issues/10516
|
||||
if (this.isComposing) return;
|
||||
|
||||
// hack for https://github.com/ElemeFE/element/issues/8548
|
||||
// should remove the following line when we don't support IE
|
||||
|
@ -299,12 +307,9 @@
|
|||
|
||||
this.$emit('input', event.target.value);
|
||||
|
||||
// set input's value, in case parent refuses the change
|
||||
// ensure native input value is controlled
|
||||
// see: https://github.com/ElemeFE/element/issues/12850
|
||||
this.$nextTick(() => {
|
||||
let input = this.getInput();
|
||||
input.value = this.value;
|
||||
});
|
||||
this.$nextTick(this.setNativeInputValue);
|
||||
},
|
||||
handleChange(event) {
|
||||
this.$emit('change', event.target.value);
|
||||
|
@ -355,6 +360,7 @@
|
|||
},
|
||||
|
||||
mounted() {
|
||||
this.setNativeInputValue();
|
||||
this.resizeTextarea();
|
||||
this.updateIconOffset();
|
||||
},
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { createVue, destroyVM, wait, waitImmediate } from '../util';
|
||||
import { createVue, destroyVM, triggerEvent, wait, waitImmediate } from '../util';
|
||||
|
||||
describe('Input', () => {
|
||||
let vm;
|
||||
|
@ -6,7 +6,7 @@ describe('Input', () => {
|
|||
destroyVM(vm);
|
||||
});
|
||||
|
||||
it('create', () => {
|
||||
it('create', async() => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<el-input
|
||||
|
@ -14,11 +14,12 @@ describe('Input', () => {
|
|||
:maxlength="5"
|
||||
placeholder="请输入内容"
|
||||
@focus="handleFocus"
|
||||
value="input">
|
||||
:value="input">
|
||||
</el-input>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
input: 'input',
|
||||
inputFocus: false
|
||||
};
|
||||
},
|
||||
|
@ -35,6 +36,18 @@ describe('Input', () => {
|
|||
expect(inputElm.value).to.equal('input');
|
||||
expect(inputElm.getAttribute('minlength')).to.equal('3');
|
||||
expect(inputElm.getAttribute('maxlength')).to.equal('5');
|
||||
|
||||
vm.input = 'text';
|
||||
await waitImmediate();
|
||||
expect(inputElm.value).to.equal('text');
|
||||
});
|
||||
|
||||
it('default to empty', () => {
|
||||
vm = createVue({
|
||||
template: '<el-input/>'
|
||||
}, true);
|
||||
let inputElm = vm.$el.querySelector('input');
|
||||
expect(inputElm.value).to.equal('');
|
||||
});
|
||||
|
||||
it('disabled', () => {
|
||||
|
@ -236,7 +249,7 @@ describe('Input', () => {
|
|||
});
|
||||
|
||||
describe('Input Events', () => {
|
||||
it('event:focus & blur', done => {
|
||||
it('event:focus & blur', async() => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<el-input
|
||||
|
@ -255,13 +268,11 @@ describe('Input', () => {
|
|||
vm.$el.querySelector('input').focus();
|
||||
vm.$el.querySelector('input').blur();
|
||||
|
||||
vm.$nextTick(_ => {
|
||||
await waitImmediate();
|
||||
expect(spyFocus.calledOnce).to.be.true;
|
||||
expect(spyBlur.calledOnce).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('event:change', done => {
|
||||
it('event:change', async() => {
|
||||
// NOTE: should be same as native's change behavior
|
||||
vm = createVue({
|
||||
template: `
|
||||
|
@ -290,13 +301,11 @@ describe('Input', () => {
|
|||
// simplified test, component should emit change when native does
|
||||
simulateEvent('1', 'input');
|
||||
simulateEvent('2', 'change');
|
||||
vm.$nextTick(_ => {
|
||||
await waitImmediate();
|
||||
expect(spy.calledWith('2')).to.be.true;
|
||||
expect(spy.calledOnce).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('event:clear', done => {
|
||||
it('event:clear', async() => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<el-input
|
||||
|
@ -319,18 +328,51 @@ describe('Input', () => {
|
|||
// focus to show clear button
|
||||
inputElm.focus();
|
||||
vm.$refs.input.$on('clear', spyClear);
|
||||
vm.$nextTick(_ => {
|
||||
await waitImmediate();
|
||||
vm.$el.querySelector('.el-input__clear').click();
|
||||
vm.$nextTick(_ => {
|
||||
await waitImmediate();
|
||||
expect(spyClear.calledOnce).to.be.true;
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('event:input', async() => {
|
||||
vm = createVue({
|
||||
template: `
|
||||
<el-input
|
||||
ref="input"
|
||||
placeholder="请输入内容"
|
||||
clearable
|
||||
:value="input">
|
||||
</el-input>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
input: 'a'
|
||||
};
|
||||
}
|
||||
}, true);
|
||||
const spy = sinon.spy();
|
||||
vm.$refs.input.$on('input', spy);
|
||||
const nativeInput = vm.$refs.input.$el.querySelector('input');
|
||||
nativeInput.value = '1';
|
||||
triggerEvent(nativeInput, 'compositionstart');
|
||||
triggerEvent(nativeInput, 'input');
|
||||
await waitImmediate();
|
||||
nativeInput.value = '2';
|
||||
triggerEvent(nativeInput, 'compositionupdate');
|
||||
triggerEvent(nativeInput, 'input');
|
||||
await waitImmediate();
|
||||
triggerEvent(nativeInput, 'compositionend');
|
||||
await waitImmediate();
|
||||
// input event does not fire during composition
|
||||
expect(spy.calledOnce).to.be.true;
|
||||
// native input value is controlled
|
||||
expect(vm.input).to.equal('a');
|
||||
expect(nativeInput.value).to.equal('a');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
describe('Input Methods', () => {
|
||||
it('method:select', done => {
|
||||
it('method:select', async() => {
|
||||
const testContent = 'test';
|
||||
|
||||
vm = createVue({
|
||||
|
@ -347,11 +389,9 @@ describe('Input', () => {
|
|||
|
||||
vm.$refs.inputComp.select();
|
||||
|
||||
vm.$nextTick(_ => {
|
||||
await waitImmediate();
|
||||
expect(vm.$refs.inputComp.$refs.input.selectionStart).to.equal(0);
|
||||
expect(vm.$refs.inputComp.$refs.input.selectionEnd).to.equal(testContent.length);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in New Issue