React Hooks 實現的中文輸入元件

知名噴子 發表於 2022-05-17
React
在前端開發中,通過監聽 onInput 事件來觸發輸入框內容的更新,是沒有問題的,但如果輸入的內容有中文的時候,會出現類似 zhong'wen'nei'rong這樣的備選內容。
這種內容的影響普遍不會很大,但是當需要對輸入的內容進行一些耗時的操作的時候,這個影響就不得不考慮一下了,比如說內容需要進行復雜的渲染、通過網路實時傳送等等場景。

對這種問題的解決方案,需要藉助瀏覽器提供的組合輸入事件 。簡單地說,輸入中日韓文等各種包含“選字”環節的文字的時候,會額外觸發兩個事件compositionStartcompositionEnd,監聽並處理這兩個事件,就可以在使用者還未完成選字的時候先等待而不觸發onInput事件:

圖片.png
源自MDN 文件: compositionstart

如果僅僅需要處理組合輸入的話,使用 compositionEnd 代替 onInput 就可以,但使用者偶爾也需要輸入英文和數字,這些輸入不會觸發 compositionEnd

因此我們需要在 compositionStart 的時候進入等待狀態,等待狀態中間的所有 onInput 一律不處理。而輸入英文和字母的時候,onInput 則正常處理。

標記等待狀態的方法比較多,例如useRef

import { useRef } from "react";

export function ChineseInput(params){
    const { onInput = () => {} } = params;
    const lockRef = useRef(false);
  
    // 進入組合輸入狀態
    const handleStart = () => {
      lockRef.current = true
    };
  
    const handleInput = event => {
      // 處於組合輸入狀態,不予處理
      if(lockRef.current) return;

      // 非組合輸入狀態,觸發 onInput
      onInput(event);
    };
  
    // 選字結束,觸發 onInput
    const handleEnd = event => {
      lockRef.current = false;
      onInput(event);
    };
  
    return (
      <input
        {...params}
        onCompositionEnd={handleEnd}
        onCompositionStart={handleStart}
        onInput={handleInput}
      />
    )
  }
當然這裡可以改成一個高階函式,這樣的話就不用單獨給 textArea 也寫一個元件了,不過常見的輸入標籤也就這倆,沒有必要複用。

這兩個事件的相容性還不錯:

圖片.png

還在用這些老瀏覽器的電腦基本可以忽略,硬要相容的話,怕是隻有用適當魔改的防抖或者節流函式來代替了。