1. 程式人生 > >輸入框裡面的值通過正則匹配改變導致的游標問題(坑!!)

輸入框裡面的值通過正則匹配改變導致的游標問題(坑!!)

前言

需求是這樣的,輸入加油卡號,每隔輸入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寫入,因此再加一點點延遲,就可以重置游標了。