2022 第50週 實作筆記:透過 compositionstart/compositionend 來暫停驗證輸入內容
總結
日前實做了一個「僅允許使用者輸入中文字」的 input 欄位,而實際使用時,發現在鍵入注音的過程中會頻繁跳出「輸入內容無效」的提示;最後透過 web api compositionstart
以及 compositionend
的搭配來達成「使用者輸入注音時,暫停檢查內容」的機制。
試玩:DEMO 原始碼:tzynwang/react-compositionstart-compositionend
筆記
實作上的邏輯非常簡單,僅是「偵測到 compositionstart
時,暫停驗證行為;反之當輸入完成(偵測到 compositionend
事件後),再透過 String.prototype.match()
來判定輸入的內容是否有效。
import React, { memo, useRef, useState, useEffect } from 'react';
import TextField from '@mui/material/TextField';
// INFO: 定義好有效字元的 regex,以下內容是允許「所有的中文字元」
const VALID_CHARS_REGEX =
/^[\u2E80-\u2FD5\u3190-\u319f\u3400-\u4DBF\u4E00-\u9FCC\uF900-\uFAAD]*$/;
function Input1(): React.ReactElement {
/* States */
const inputRef = useRef<HTMLInputElement | null>(null);
const [canVerify, setCanVerify] = useState<boolean>(true);
const [userInput, setUserInput] = useState<string>('');
// INFO: 只有在應該要開始驗證的時候,才回傳字元驗證結果,否則一律回傳 true 讓輸入欄位不要出現錯誤與提示文字
const isValidInput = canVerify ? !!userInput.match(VALID_CHARS_REGEX) : true;
/* Functions */
const handleUserInput = (e: React.ChangeEvent<HTMLInputElement>): void => {
setUserInput(e.target.value);
};
const startVerify = (): void => {
setCanVerify(true);
};
const stopVerify = (): void => {
setCanVerify(false);
};
/* Hooks */
useEffect(() => {
const ref = inputRef.current;
// INFO: 偵測到 compositionstart 時,停止驗證;反之當 compositionend 時,開始內容驗證
ref?.addEventListener('compositionstart', stopVerify);
ref?.addEventListener('compositionend', startVerify);
return () => {
ref?.removeEventListener('compositionstart', stopVerify);
ref?.removeEventListener('compositionend', startVerify);
};
}, []);
/* Main */
return (
<TextField
error={!isValidInput}
fullWidth
helperText={isValidInput ? '' : '只能輸入中文字'}
label="輸入一些中文(在你輸入注音時,不會進行內容判定)"
margin="normal"
onChange={handleUserInput}
ref={inputRef}
value={userInput}
variant="standard"
/>
);
}
export default memo(Input1);
簡單,但能提升使用者進行中文輸入的體驗。