input输入框大家应该都很熟悉了吧,不知道大家有没有遇到过这样的一种情况:如上图,在中文输入过程中,输入的拼音也会触发input框的input事件,有些时候我们并不希望在中文输入的过程中拼音触发input事件。
在日常开发中,输入框是一个常见的组件,但是在拼音输入过程中,每次输入都会触发input事件,这可能会导致不必要的操作。本文将介绍一种解决该问题的Vue指令,使得在拼音输入过程中不会触发input事件,从而优化输入框体验。
我们需要了解compositionstart和compositionend两个事件。当用户开始输入拼音时,会触发compositionstart事件,此时输入框的值并没有真正改变。随着输入的进行,最终会触发compositionend事件,此时输入框的值才会真正改变。我们可以通过监听这两个事件,来控制何时触发input事件。
具体实现方式是,在监听到compositionstart事件时,将输入框的值存储下来,然后在监听到compositionend事件时,再将输入框的值与之前存储的值进行比较,如果不同,则触发自定义的input事件,并将新值作为参数传递给监听器。
html复制代码<div class="input-text-title">正常情况</div>
<div class="input-text-content">{{ inputText }}</div>
<input
placeholder="请输入"
class="input-text"
@input="doInput"
id="inputContent"
/>
简单定义一个输入框,监听其input事件,inputText保存实时输入内容并展示到页面上。
javascript复制代码const inputContent=document.getElementById("inputContent");
inputContent.addEventListener("compositionstart", ()=> {
this.isComposing=true;
this.inputComplate(inputContent.value);
});
inputContent.addEventListener("compositionend", ()=> {
this.isComposing=false;
if (inputContent.value !==this.inputText) {
this.inputComplate(inputContent.value);
}
});
首先,我们通过getElementById方法获取到id为"inputContent"的输入框元素,并将其赋值给inputContent常量。
然后,我们给inputContent元素添加compositionstart事件的监听器。在事件触发时,会执行回调函数。在回调函数中,我们将isComposing变量设置为true,表示正在进行拼音输入,然后调用inputComplate方法处理输入框的值,并将输入框的值作为参数传递给inputComplate方法。
接下来,我们给inputContent元素添加compositionend事件的监听器。在事件触发时,同样会执行回调函数。在回调函数中,我们将isComposing变量设置为false,表示拼音输入结束,然后同样调用inputComplate方法处理输入框的值,并将输入框的值作为参数传递给inputComplate方法。
通过监听这两个事件,并在事件触发时调用相应的处理方法,我们可以实现在拼音输入过程中控制input事件的触发时机,从而达到不触发input事件的效果。
javascript复制代码inputComplate(value) {
this.inputText=value;
},
doInput(event) {
if (this.isComposing) return;
const value=event.target.value;
this.inputComplate(value);
},
输入框input事件绑定的是doInput方法,这个方法在这里只是用于过渡一下,在这里我们需要判断当前是否正在输入拼音,如果是在输入拼音的话我们就直接返回,不进行后续操作,如果不是的话则调用inputComplate进行后续处理,真正的处理逻辑应该是在inputComplate方法中。
这样我们就简单的完成了一个忽略拼音输入过程中的input事件的功能
本文到此结束
且慢,虽然上面这样操作之后可以得到一个可以忽略拼音输入过程中的input事件的输入框;但是,如果我们有很多个输入框需要加上这个功能呢?这样的话我们每写一个input框,想要加上这个功能的话不还得加一堆乱七八糟的代码来处理,这明显很不合理。
javascript复制代码export default {
bind(el, binding) {
let isComposing=false;
let value="";
el.addEventListener("compositionstart", ()=> {
isComposing=true;
value=el.value;
});
el.addEventListener("compositionend", ()=> {
isComposing=false;
if (value !==el.value) {
binding.value(el.value);
}
});
// 添加自定义的input事件监听器
el.addEventListener("input", (event)=> {
if (isComposing) {
return;
}
const value=event.target.value;
// 处理输入框的值
binding.value(value);
});
},
};
html复制代码<input
placeholder="输入试试"
class="input-text"
v-JIgnorePinyin="doInput1"
/>
在bind钩子函数中,我们首先定义了两个变量isComposing和value,分别用于记录是否正在进行拼音输入和输入框的值。
然后,我们给输入框元素el添加compositionstart事件的监听器。在事件触发时,将isComposing设置为true,表示正在进行拼音输入,并将输入框的值赋给value。
接下来,我们给输入框元素el添加compositionend事件的监听器。在事件触发时,将isComposing设置为false,表示拼音输入结束。然后,我们比较value和输入框的当前值el.value是否相等,如果不相等,则说明输入框的值已经发生了变化,此时我们调用binding.value方法,将当前输入框的值el.value作为参数传递给绑定该指令的处理函数。
最后,我们给输入框元素el添加input事件的监听器。在事件触发时,首先判断isComposing的值,如果为true,则直接返回,不做任何处理。如果isComposing的值为false,说明拼音输入已经完成,此时我们获取输入框的值event.target.value,并将其作为参数调用binding.value方法,从而处理输入框的值。
通过定义这个自定义指令,我们可以在Vue组件中使用它来监听拼音输入过程中的事件,并执行相应的处理逻辑,从而实现更加灵活的输入框交互。
这样的话后面需要加功能只需要一个指令即可搞定。
目前该组件也已经收录到我的组件库,组件文档地址如下: jyeontu.xyz/jvuewheel/#…
组件库中还有许多好玩有趣的组件,如:
等等……
组件库已开源到gitee,有兴趣的也可以到这里看看:gitee.com/zheng_yongt…
觉得有帮助的可以点个star~
有什么问题或错误可以指出,欢迎pr~
有什么想要实现的组件或想法可以联系我~
作者:JYeontu
链接:https://juejin.cn/post/7330439494666223642
开发过程中,基本都遇到过需要限制输入的情况,比如金额、仅字母数字、可输入小数位等,网上搜了很多方法也遇到一些坑,所以分享出来。
在VUE中可以在v-modal后添加修饰符的形式来限制输入,比如:
<input v-model.number="testValue" type="number">
.number可以实现限制数字输入,但是会有以下问题:
/* 普通IE浏览器 样式清除 */
input::-webkit-outer-spin-button,input::-webkit-inner-spin-button{
-webkit-appearance: none !important;
}
/* 火狐浏览器样式清除 */
input[type="number"]{
-moz-appearance:textfield;
}
通过@input监听更新数据,实现只能输入数字,而且可以自行定制限制输入内容
<input v-model="testValue" @input="testValue = testValue.replace(/[^\d]/g,'')">
此方法可以满足需求,但是无法封装进行批量使用
封装input限制输入指令
//input.js
const addListener = function(el, type, fn) {
el.addEventListener(type, fn, false)
}
//去掉空格
const spaceFilter = function(el) {
addListener(el, 'input', () => {
el.value = el.value.replace(/\s+/, '')
})
}
// 限制只能输入整数和小数(价格类、最多两位小数)
const priceFilter = function(el) {
addListener(el, 'input', () => {
el.value = (el.value.match(/^\d*(\.?\d{0,2})/g)[0]) || null
if (isNaN(el.value)) {
el.value = ''
}
})
}
export default {
bind(el, binding) {
if (el.tagName.toLowerCase() !== 'input') {
el = el.getElementsByTagName('input')[0]
}
spaceFilter(el)
switch (binding.arg) {
case 'price':
priceFilter(el)
break
default:
console.warn('未知指令类型',binding.arg)
break
}
}
}
注册全局自定义指令
//main.js
import inputFilter from '@/directives/InputFilter.js'
Vue.directive('inputFilter', inputFilter)
使用v-input-filter指令
<input v-modal="testValue" v-input-filter:price>
这样封装在使用时会出现一个隐蔽的bug,就是在输入指令中正则限制以外的字符时,视图中输入框显示是正确的,但是在浏览器控制栏Vue Devtools中的testValue最后一位字符是最后输入的时的字符。
比如输入abc、123abc输入框内是 、123,但实际testValue值是c、123c。
原因是vue中绑定的值是通过监听input进行赋值的,直接修改输入框值不会触发input事件,需要通过dispatchEvent再次手动触发input事件,修改如下:
//input.js
···
// 防抖
let debounce = (fn, delay) => {
var delay = delay || 100;
var timer;
return function() {
var th = this;
var args = arguments;
if (timer) {
clearTimeout(timer);
}
timer = setTimeout(function() {
timer = null;
fn.apply(th, args);
}, delay);
};
}
···
// 限制只能输入整数和小数(价格类、两位小数)
const priceFilter = function(el) {
addListener(el, 'input', debounce(() => {//添加防抖 防止反复触发事件导致内存溢出
el.value = (el.value.match(/^\d*(\.?\d{0,2})/g)[0]) || null
if (isNaN(el.value)) {
el.value = ''
}
//触发input事件
el.dispatchEvent(new Event('input'))
}))
}
···
到这里算是满足了要求,也能方便的使用,分享出来希望能够抛砖引玉,学习到更好的方式,如果有更好的方法请告诉我,谢谢!
*请认真填写需求信息,我们会在24小时内与您取得联系。