问题背景:
在表格翻页组件中,有一个跳页输入框,当输入不合法字符时,利用绑定的指令去除不合法字符。
但是v-model不生效,在此记录一下,给前端的小伙伴们踩踩坑。
问题描述:
输入不合法字符时,期望输入框内的值和绑定的变量都回填之前的数字。例如输入‘?’,期望输入框和变量都显示‘1’;实际输入框显示‘1,变量显示‘1?’,v-model未生效。
<input
type="text"
v-pager-formatter="{
pagerFormatterMax: totalPage || 1
}"
v-model="index"
@blur="setPage()"
@keyup.enter="$event.target.blur()"
/>
v-pager-formatter就是输入框校验指令,当输入内容时,在指令中校验输入是否合法。
export default {
updated(el: HTMLInputElement, binding: DirectiveBinding): void {
const Service: InputValidator = new InputValidator();
// 最大页数
const totalPageNumber: number = binding.value.pagerFormatterMax;
// 输入框值
let targetValue: string;
const inputChange = (elRef): boolean => {
// 校验是否合法,不合法替换不合法字符,返回合法字符
const limitNumber: string = Service.limitNumber(targetValue, 'int', 1, totalPageNumber);
if (limitNumber !== targetValue) {
// 如果有不合法字符,则回填合法字符
if (limitNumber) {
elRef.value = limitNumber;
} else {
elRef.value = '';
}
}
return true;
};
el.oninput = (event: Event): void => {
targetValue = event.target['value'];
inputChange(el);
};
},
};
在指令中,elRef.value = limitNumber后,v-model绑定的变量并不会更新。
问题原因:
v-model双向绑定原理实际上就是 "@input" 事件与 ":value" 属性的结合体。v-model未生效其实(:value绑定的变量未更新)其实就是在指令中改变输入框value时未触发“@input”事件,导致v-moel未生效。
解决方法:
手动触发input事件,使绑定的变量更新。EventTarget.dispatchEvent()方法会向一个指定的事件目标派发一个Event,并以合适的顺序(同步地)调用所有受影响的EventListener。
代码中加入elRef.dispatchEvent(new Event('input'))触发input事件,使v-model更新。这样就能解决这个问题。
export default {
updated(el: HTMLInputElement, binding: DirectiveBinding): void {
const Service: InputValidator = new InputValidator();
// 最大页数
const totalPageNumber: number = binding.value.pagerFormatterMax;
// 输入框值
let targetValue: string;
const inputChange = (elRef): boolean => {
// 校验是否合法,不合法替换不合法字符,返回合法字符
const limitNumber: string = Service.limitNumber(targetValue, 'int', 1, totalPageNumber);
if (limitNumber !== targetValue) {
// 如果有不合法字符,则回填合法字符
if (limitNumber) {
elRef.value = limitNumber;
} else {
elRef.value = '';
}
elRef.dispatchEvent(new Event('input'));
}
return true;
};
el.oninput = (event: Event): void => {
targetValue = event.target['value'];
inputChange(el);
};
},
};