輸入框裡面的值通過正則匹配改變導致的游標問題(坑!!)
阿新 • • 發佈:2019-02-01
前言
需求是這樣的,輸入加油卡號,每隔輸入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寫入,因此再加一點點延遲,就可以重置游標了。