前言
需求是这样的,输入加油卡号,每隔输入4位自动加上一个横杠,如图:
这个光标问题是个坑,,加班到10点还没解决好。。。
解决方法
首先,这里我使用的方法是监听输入,使用正则匹配。
<p className="addcard_tip">卡号:</p>
<input type="tel" id="cardNum" value={this.state.cardid} className="input_info" onClick={() => { this.inputClick() }} onChange={(e) => { this.inputCardid(e) }} style={{ "left": "66px" }} maxLength={this.state.type ? CARDID_LEN_SHIYOU+3 : CARDID_LEN_SHIHUA+4} placeholder={`请输入${this.state.type ? CARDID_LEN_SHIYOU : CARDID_LEN_SHIHUA}位卡号`} />
inputCardid(e) {
var input = document.getElementById('cardNum'), deforeValue = '';
let cardid = input.value.replace(/\-/g, '').replace(/(.{4})(?=.)/g, '$1-'); //把input输入框的值,通过正则每隔4位插入横杠'-'
if (e) {
var start = this.getSelectionStart(input); //获取现在光标的位置
this.setState({
cardid: input.value.replace(/\-/g, '').replace(/(.{4})(?=.)/g, '$1-') //把通过正则匹配后的值设置为input的value,同时也和state做一个双向绑定
},()=>{
this.setSelectionStart(input, start);//setState完了以后,再重新设置实际上的光标
}
} else {
cardid = this.state.cardid;
}
}
getSelectionStart(input) {
var realStart = input.value.substring(0, input.selectionStart || 0).replace(/\-/g, '').length;
return realStart + (parseInt((realStart - 1) / 4));//这里,获取的是实际上正则匹配后光标的位置
}
setSelectionStart(input,start) {
input.setSelectionRange(start, start)
}
inputClick(){
var input = document.getElementById('cardNum');
var start = this.getSelectionStart(input);
this.setSelectionStart(input,start);
}
这里,在ios上是完美表现的,然而在安卓上就会光标出现问题,就是我输入了第五位,在第五位前面通过js改变了input的值,但是,我的光标还是停留在'-'的后面,不是预期的在输入的值的最后。
然后,我就开始了一个疯狂的踩坑模式,陷入一个死循环...把光标强制在最后一位,但是这样无法修改中间的值..
后来,开始怀疑是不是设置光标的时机不对,但是已经设置在setState完成的回调里面了。
后来,尝试给设置光标的方法再加一点延迟。
inputCardid(e) {
var input = document.getElementById('cardNum'), deforeValue = '';
let cardid = input.value.replace(/\-/g, '').replace(/(.{4})(?=.)/g, '$1-'); //把input输入框的值,通过正则每隔4位插入横杠'-'
if (e) {
var start = this.getSelectionStart(input); //获取现在光标的位置
this.setState({
cardid: input.value.replace(/\-/g, '').replace(/(.{4})(?=.)/g, '$1-') //把通过正则匹配后的值设置为input的value,同时也和state做一个双向绑定
},()=>{
setTimeout(() => {
this.setSelectionStart(input, start);
}, 30);//setState完了以后,再重新设置实际上的光标
}
} else {
cardid = this.state.cardid;
}
}
然后,就解决了。。
这里, 在setState完成后进行光标重置,但是还没有把input里面的value写入,因此再加一点点延迟,就可以重置光标了。