From b4dcd565d63132160a4547df83d9e9bc21ad9082 Mon Sep 17 00:00:00 2001 From: ittoview Date: Mon, 2 Mar 2026 01:24:48 +0000 Subject: [PATCH] =?UTF-8?q?fix(=E7=BB=83=E4=B9=A0):=20=E4=BD=BF=E7=94=A8na?= =?UTF-8?q?tiveEvent.isComposing=E5=90=8C=E6=AD=A5=E5=88=A4=E6=96=AD?= =?UTF-8?q?=E8=BE=93=E5=85=A5=E6=B3=95=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 在InputArea中读取nativeEvent.isComposing同步判断组合状态 - 添加isComposingRef避免状态更新时序问题 - 确保输入法组合期间不触发自动跳转和字符分散 via [HAPI](https://hapi.run) Co-Authored-By: HAPI --- src/components/practice/InputArea.tsx | 16 +++++++++++++--- src/pages/ProcessPracticePage.tsx | 7 +++++-- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/components/practice/InputArea.tsx b/src/components/practice/InputArea.tsx index 0d8ab19..15b5af8 100644 --- a/src/components/practice/InputArea.tsx +++ b/src/components/practice/InputArea.tsx @@ -37,13 +37,23 @@ export function InputArea({ } }, [userInput]) - const handleCharInput = (index: number, value: string) => { + const handleCharInput = ( + index: number, + e: React.ChangeEvent + ) => { if (inputLocked) return + const value = e.target.value + const nativeIsComposing = + typeof (e.nativeEvent as InputEvent).isComposing === 'boolean' + ? (e.nativeEvent as InputEvent).isComposing + : false + const composing = isComposing || nativeIsComposing + const newInput = [...userInput] // 输入法组合期间,只更新当前输入框的值,不做任何跳转 - if (isComposing) { + if (composing) { newInput[index] = value onInputChange(newInput) return @@ -125,7 +135,7 @@ export function InputArea({ ref={(el) => (inputRefs.current[index] = el)} type="text" value={char} - onChange={(e) => handleCharInput(index, e.target.value)} + onChange={(e) => handleCharInput(index, e)} onKeyDown={(e) => handleKeyDown(index, e)} onCompositionStart={onCompositionStart} onCompositionEnd={onCompositionEnd} diff --git a/src/pages/ProcessPracticePage.tsx b/src/pages/ProcessPracticePage.tsx index 7430f87..9e260d2 100644 --- a/src/pages/ProcessPracticePage.tsx +++ b/src/pages/ProcessPracticePage.tsx @@ -48,6 +48,7 @@ export default function ProcessPracticePage() { const [userInput, setUserInput] = useState([]) const [charStatuses, setCharStatuses] = useState([]) const [isComposing, setIsComposing] = useState(false) + const isComposingRef = useRef(false) const [lastErrorTimestamp, setLastErrorTimestamp] = useState( null ) @@ -198,19 +199,21 @@ export default function ProcessPracticePage() { latestInputRef.current = newInput setUserInput(newInput) - if (isComposing) return + if (isComposingRef.current) return validateInput(newInput) }, - [isComposing, validateInput] + [validateInput] ) // 输入法状态管理 const handleCompositionStart = useCallback(() => { + isComposingRef.current = true setIsComposing(true) }, []) const handleCompositionEnd = useCallback(() => { + isComposingRef.current = false setIsComposing(false) // 输入法确认后,需要将当前输入框中的所有字符分散到后续输入框 requestAnimationFrame(() => {