国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

在格式化的場景下,React input 的光標的處理辦法

cheng10 / 1760人閱讀

摘要:具體表現是什么樣的呢圖安卓下不期望的輸入行為可以看到,在安卓手機下每次格式化發生的時候,本來應該一直在最后的光標會錯格一位,導致連續輸入出現問題。

今天要來說的是有關于有數值格式化的場景中,React input 光標的一些異常的表現和對應的處理辦法。故事要從一個 issue 說起,有用戶反映在使用 NumberField 組件輸入時安卓下會出現光標位置異常,導致連續輸入會達不到期望的結果。具體表現是什么樣的呢?

圖1 安卓下不期望的輸入行為

可以看到,在安卓手機下每次格式化發生的時候,本來應該一直在最后的光標會錯格一位,導致連續輸入出現問題。而這個問題在 PC Chrome 和 iOS 上都沒有出現,于是可以判定是一個兼容性問題。但這個兼容性問題是如何產生的呢?

分析一下格式化的話的過程,如上面的情況,輸入 18758 時,因為要做針對卡號的格式化,所以會將原有的值轉變為 "1875 8",從字符串長度上來看,從 5 位變成了 6 位,那么如果此時光標位置沒有在值變化時跳到最后一位,則會停留在空格處,看起來就好像錯格了一位,連續輸入時就會有問題。

單從輸入框的光標變化行為來看,這好像也不算是一種異常的變化,只是不響應值的變化跳到尾部而已。但引申出來的問題是為什么在 iOS 和 PC Chrome 下又會跳動到尾部呢。

圖2: 相同的代碼在 PC Chrome 下表現與安卓不同。

于是去網上搜索,輾轉在 React 的 github 中找到這樣一個 issue, Cursor jumps to end of controlled input。在這里 React 的主要維護者之一的 @sophiebits(spicyj) 給出了一個比較確切的答案。

圖3 sophiebits 關于 React controlled input value 變化時光標行為的解釋

原來因為 value 的變化具有非常大的不確定性,因此 React 無法使用一種可靠且通用的邏輯去保存光標的位置在一個合適的位置,因此 React 在受控模式下的重新渲染都會時光標移動到最后的位置。這個至少解釋了PC Chrome 和 iOS 下光標跳動到結尾的原因,但安卓下為什么沒有表現出同樣的行為到目前位置我還沒有找到合理的解釋。

那有沒有辦法使安卓上的表現和 iOS 中一致呢?又是一陣翻閱和嘗試,最后發現如果將重新渲染的過程和 input 的 onChange 置于前后兩個 tick 中就可以使安卓中 input 的表現和其他平臺上表現一致,即表現為光標在重新渲染時跳到最后,示意代碼如下。

import React from "React";
class Demo extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            value: "xxx",
        };
    }
    
    handleChange(e) {
        const value = e.target.value;
        // 通過 setTimeout 異步
        // 使 re-render 和 onChange 處于兩個 tick 中
        setTimeout(() => {
            this.setState({
                value,
            });
        });
    }
    
    render() {
        return (
             { this.handleChange(e); }}  
            />
        );
    }
}

這樣終于使得表現的行為在安卓和 iOS 上表現一致,并且正常輸入的情況下表現得比較符合期望了,然而等等,這樣就可以了嗎?從之前的 React issue 中得出的結論可以看出,無論是如何的修改都會跳至 input 的結尾,這樣如果是從中間修改的話會變成什么樣?

圖4:中間編輯時又會出現問題

從上面的圖里可以看出,因為 React 無論何種修改都會將光標置尾,如果從中間進行修改,那么表現地又會很不符合用戶預期,沒有辦法做到連續輸入。這回倒是兩端行為保持一致,都是不期望的狀態。。

但是都不正常也有好處,不需要根據平臺去寫一些 ifelse,可以統一地去做處理。從上面的討論中我們可以知道 React 沒有保存光標的位置是因為沒有一個通用并且可靠的算法去支撐這一行為。這是因為 input 的變化可能是增加空格做格式化,也可能是過濾過些字符,也可能是觸發某些條件直接變成了其他字符等各種無法預測的變化行為。但是細化到數字格式化這一單一場景時,光標位置的保存邏輯就變得簡單和清晰的多了。

在用戶輸入的過程中,只存在兩種情況,在結尾中追加和在中間修改。在結尾追加的 case 中,例如 18758^ 時,由于一直是在向后追加的狀態,我們只要一直保持光標在最后即可(即默認狀態 1875 8^ ),在中間編輯的 case 下,光標并不處于結尾,如 187^5 8,此時如果在 7 后面追加了一個 8,那么理想的圖標應該維持在 8 之后(即 1878^ 58),此時就應該保存光標的位置在上次 format 之前的狀態。

邏輯清楚了,接下來就是如何實現的問題了。那么如何探測和修改光標位置呢?這就涉及了 input 中選區相關的屬性,我們知道我們可以通過一些方式(如鼠標拖拽和長按屏幕等)在 input 中完成對一段話的選區,因此光標的位置其實是由選區的開始點(selectionStart)和結束點(selectionEnd)決定的。那么其實我們就可以通過讀取,儲存和設置這兩個屬性來達到我們想要實現的目的,實例代碼如下。

class Demo extends React.Component {
    ...
    
    componentDidUpdate(prevProps) {
        const { value } = prevProps;
        const { inputSelection } = this;
        if (inputSelection) {
          // 在 didUpdate 時根據情況恢復光標的位置
          // 如果光標的位置小于值的長度,那么可以判定屬于中間編輯的情況
          // 此時恢復光標的位置
          if (inputSelection.start < this.formatValue(value).length) {
            const input = this.input;
            input.selectionStart = inputSelection.start;
            input.selectionEnd = inputSelection.end;
            this.inputSelection = null;
          }
        }
    }
    
    handleChange(e) {
        // 在 onChange 時記錄光標的位置
        if (this.input) {
          this.inputSelection = {
            start: this.input.selectionStart,
            end: this.input.selectionEnd,
          };
        }
        ...
    }
    
    render() {
        return (
             { this.input = c; }}
                value={this.state.value} 
                onChange={(e) => { this.handleChange(e); }}  
            />
        );
    }
}

至此,我們終于在追加和中間編輯的情況下都實現了我們想要的效果。這是一個比較小的技術點,但是由于里面涉及了一些 React 內部的處理邏輯及平臺差異性問題,排查和解決起來并不是那么容易,希望可以給有類似問題的同學在處理時有所啟發。

文中涉及的各端及瀏覽器信息

Android

Mozilla/5.0 (Linux; U; Android 8.1.0; zh-CN; CLT-AL00 Build/HUAWEICLT-AL00) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/57.0.2987.108 UCBrowser/11.9.4.974 UWS/2.13.1.48 Mobile Safari/537.36 

iOS

Mozilla/5.0 (iPhone; CPU iPhone OS 11_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15F79

PC Chrome

Mozilla/5.0 (Linux; Android 5.0; SM-G900P Build/LRX21T) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.3497.100 Mobile Safari/537.36
文中涉及的組件庫

SaltUI: https://github.com/salt-ui/sa...

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/98573.html

相關文章

  • input 彈起數字鍵盤那些坑

    摘要:踩的大坑前言最近有個需求要將全平臺的交易密碼由原來的位復雜密碼改為位純數字交易密碼,涉及到非常多的業務場景,但修改起來也無非兩種設置交易密碼,使用交易密碼設置交易密碼普通長條輸入框彈起數字鍵盤支持明暗文切換查看使用交易密碼顯示六個格子彈起 input ios 踩的大坑 前言:最近有個需求要將全平臺的交易密碼由原來的 6-16位 復雜密碼改為6位純數字交易密碼,涉及到非常多的業務場景,但...

    imccl 評論0 收藏0
  • 基于uiwebview富文本編輯器實踐

    摘要:背景最近我們微信讀書將寫想法換成了基于的富文本編輯器,遇到了不少問題,這里我將簡單的介紹一下我們在開發過程中踩到的坑。 背景 最近我們微信讀書將寫想法換成了基于webview的富文本編輯器,遇到了不少問題,這里我將簡單的介紹一下我們在開發過程中踩到的坑。 實現富文本編輯器有兩個基本思路: 基于native實現:比如coretext或者textkit 基于uiwebview實現 第一...

    luzhuqun 評論0 收藏0
  • 從 setState promise 化探討 體會 React 團隊設計思想

    摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...

    caiyongji 評論0 收藏0
  • 從 setState promise 化探討 體會 React 團隊設計思想

    摘要:我們來從設計思想上,和官方團隊的回應上,了解一下否決理由。此外,還有一個方法新的接口設計支持接收一個回調函數,當其子組件掛載時,這個回調函數就會相應觸發。 從 setState 那個眾所周知的小秘密說起... 在 React 組件中,調用 this.setState() 是最基本的場景。這個方法描述了 state 的變化、觸發了組件 re-rendering。但是,也許看似平常的 th...

    forrest23 評論0 收藏0
  • Web聊天工具富文本輸入框

    摘要:由于我們的富文本輸入框比較簡單,所以只需要處理兩類數據即可,其一是普通的文本類型數據,包括表情其二則是圖片類型數據。 最近折騰 Websocket,打算開發一個聊天室應用練練手。在應用開發的過程中發現可以插入 emoji ,粘貼圖片的富文本輸入框其實蘊含著許多有趣的知識,于是便打算記錄下來和大家分享。 倉庫地址:chat-input-box預覽地址:https://codepen.io...

    iKcamp 評論0 收藏0

發表評論

0條評論

最新活動
閱讀需要支付1元查看
<