在前端開發中,通過監聽onInput
事件來觸發輸入框內容的更新,是沒有問題的,但如果輸入的內容有中文的時候,會出現類似zhong'wen'nei'rong
這樣的備選內容。
這種內容的影響普遍不會很大,但是當需要對輸入的內容進行一些耗時的操作的時候,這個影響就不得不考慮一下了,比如說內容需要進行復雜的渲染、通過網路實時傳送等等場景。
對這種問題的解決方案,需要藉助瀏覽器提供的組合輸入事件 。簡單地說,輸入中日韓文等各種包含“選字”環節的文字的時候,會額外觸發兩個事件compositionStart
和compositionEnd
,監聽並處理這兩個事件,就可以在使用者還未完成選字的時候先等待而不觸發onInput
事件:
源自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
也寫一個元件了,不過常見的輸入標籤也就這倆,沒有必要複用。
這兩個事件的相容性還不錯:
還在用這些老瀏覽器的電腦基本可以忽略,硬要相容的話,怕是隻有用適當魔改的防抖或者節流函式來代替了。