Vue限制input仅能输入正整数或浮点数指令
https://zhuanlan.zhihu.com/p/150844281该指令主要解决了以下问题:v-model同步问题中文输入法导致input触发了但v-model同步失效可扩展到其他UI框架下,如element注意,我们通过手工触发input事件会再次进入指令,如此就成了死循环,所以此处需要判断是否需要去更新v-model,进而确定是不是需要手工去触发事件。 以上代码看上去是ok的,但实际
https://zhuanlan.zhihu.com/p/150844281
该指令主要解决了以下问题:
- v-model同步问题
- 中文输入法导致input触发了但v-model同步失效
- 可扩展到其他UI框架下,如element
注意,我们通过手工触发 input
事件会再次进入指令,如此就成了死循环,所以此处需要判断是否需要去更新 v-model
,进而确定是不是需要手工去触发事件。 以上代码看上去是ok的,但实际使用时会遇到一个很奇怪的现象:当用中文输入法时,尝试输入中文的字符确实会被过滤掉,但 v-model
并没有同步,再输入数字时又正常了(在element下若输入中文, v-model将永久不会再同步更新)。这个现象暴露出一个很明显的问题,当我们尝试输入中文是,每敲一个字母就会触发一次input事件,而我们期望的是在确认输入的时候才去校验。幸运的是浏览器提供了一组事件去处理这样的情况 compositionstart
、 compositionend
。
MDN释义如下: compositionstart 事件触发于一段文字的输入之前(类似于 keydown 事件,但是该事件仅在若干可见字符的输入之前,而这些可见字符的输入可能需要一连串的键盘操作、语音识别或者点击输入法的备选词)。 当文本段落的组成完成或取消时, compositionend 事件将被触发 (具有特殊字符的触发, 需要一系列键和其他输入, 如语音识别或移动中的字词建议)。
通过测试发现,我们可以通过这组事件去控制是否触发 input
事件,同时也避免了中文输入法导致 v-model
无法同步的情况发生。一个完整的输入整数指令如下:
使用
<input type="text" v-numberOnly v-model="TrialCount"/>
Vue.directive('numberOnly', {
bind(el, binding, vnode) {
let input = vnode.elm;
input.addEventListener('compositionstart', () => {
vnode.inputLocking = true
})
input.addEventListener('compositionend', () => {
vnode.inputLocking = false
input.dispatchEvent(new Event('input'))
})
input.addEventListener('input', () => {
if(vnode.inputLocking) {
return;
}
let oldValue = input.value;
let newValue = input.value.replace(/[^\d]/g, '');
if(newValue) {
switch (binding.value) {
case 'zeroBefore':
break; // 数字随意输,不做处理,如 000013
case 'zeroCan':
newValue = Number(newValue).toString(); // 去掉开头0 正整数 + 0
break;
default :
newValue = newValue.replace(/^\b(0+)/gi, ''); // (默认)去掉开头0 正整数
}
}
// 判断是否需要更新,避免进入死循环
if(newValue !== oldValue) {
input.value = newValue
input.dispatchEvent(new Event('input')) // 通知v-model更新
}
})
}
})
//需要0的情况
if(newValue) {
switch (binding.value) {
case 'zeroBefore':
break; // 数字随意输,不做处理,如 000013
// case 'zeroCan':
// newValue = Number(newValue).toString(); // 限制注释
// break;
default :
newValue = newValue.replace(/^\b/gi, ''); // 可以0开头正整数
}
}
至此,以上问题都以解决。当我们想要对更多情况做控制时,只需更改value的值即可。
扩展一个两位浮点数指令
Vue.directive('inputFloat', {
bind(el, binding, vnode) {
let input = vnode.elm;
input.addEventListener('compositionstart', () => {
vnode.inputLocking = true
})
input.addEventListener('compositionend', () => {
vnode.inputLocking = false
input.dispatchEvent(new Event('input'))
})
input.addEventListener('input', () => {
if(vnode.inputLocking) {
return;
}
let oldValue = input.value;
let newValue = input.value;
newValue = newValue.replace(/[^\d.]/g, '');
newValue = newValue.replace(/^\./g, '');
newValue = newValue.replace('.', '$#$').replace(/\./g, '').replace('$#$', '.');
newValue = newValue.replace(/^(\-)*(\d+)\.(\d\d).*$/, '$1$2.$3')
if(newValue) {
let arr = newValue.split('.')
newValue = Number(arr[0]) + (arr[1] === undefined ? '' : '.' + arr[1]) // 去掉开头多余的0
}
// 判断是否需要更新,避免进入死循环
if(newValue !== oldValue) {
input.value = newValue
input.dispatchEvent(new Event('input')) // 通知v-model更新
}
})
// input 事件无法处理小数点后面全是零的情况 因为无法确定用户输入的0是否真的应该清除,如3.02。放在blur中去处理
input.addEventListener('blur', () => {
let oldValue = input.value;
let newValue = input.value;
if(newValue) {
newValue = Number(newValue).toString()
}
// 判断是否需要更新,避免进入死循环
if(newValue !== oldValue) {
input.value = newValue
input.dispatchEvent(new Event('input')) // 通知v-model更新
}
})
}
})
更多推荐
所有评论(0)