fix(练习): 使用nativeEvent.isComposing同步判断输入法状态

- 在InputArea中读取nativeEvent.isComposing同步判断组合状态
- 添加isComposingRef避免状态更新时序问题
- 确保输入法组合期间不触发自动跳转和字符分散

via [HAPI](https://hapi.run)

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
ittoview
2026-03-02 01:24:48 +00:00
parent 426a7b0327
commit b4dcd565d6
2 changed files with 18 additions and 5 deletions

View File

@@ -37,13 +37,23 @@ export function InputArea({
} }
}, [userInput]) }, [userInput])
const handleCharInput = (index: number, value: string) => { const handleCharInput = (
index: number,
e: React.ChangeEvent<HTMLInputElement>
) => {
if (inputLocked) return 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] const newInput = [...userInput]
// 输入法组合期间,只更新当前输入框的值,不做任何跳转 // 输入法组合期间,只更新当前输入框的值,不做任何跳转
if (isComposing) { if (composing) {
newInput[index] = value newInput[index] = value
onInputChange(newInput) onInputChange(newInput)
return return
@@ -125,7 +135,7 @@ export function InputArea({
ref={(el) => (inputRefs.current[index] = el)} ref={(el) => (inputRefs.current[index] = el)}
type="text" type="text"
value={char} value={char}
onChange={(e) => handleCharInput(index, e.target.value)} onChange={(e) => handleCharInput(index, e)}
onKeyDown={(e) => handleKeyDown(index, e)} onKeyDown={(e) => handleKeyDown(index, e)}
onCompositionStart={onCompositionStart} onCompositionStart={onCompositionStart}
onCompositionEnd={onCompositionEnd} onCompositionEnd={onCompositionEnd}

View File

@@ -48,6 +48,7 @@ export default function ProcessPracticePage() {
const [userInput, setUserInput] = useState<string[]>([]) const [userInput, setUserInput] = useState<string[]>([])
const [charStatuses, setCharStatuses] = useState<CharStatus[]>([]) const [charStatuses, setCharStatuses] = useState<CharStatus[]>([])
const [isComposing, setIsComposing] = useState(false) const [isComposing, setIsComposing] = useState(false)
const isComposingRef = useRef(false)
const [lastErrorTimestamp, setLastErrorTimestamp] = useState<number | null>( const [lastErrorTimestamp, setLastErrorTimestamp] = useState<number | null>(
null null
) )
@@ -198,19 +199,21 @@ export default function ProcessPracticePage() {
latestInputRef.current = newInput latestInputRef.current = newInput
setUserInput(newInput) setUserInput(newInput)
if (isComposing) return if (isComposingRef.current) return
validateInput(newInput) validateInput(newInput)
}, },
[isComposing, validateInput] [validateInput]
) )
// 输入法状态管理 // 输入法状态管理
const handleCompositionStart = useCallback(() => { const handleCompositionStart = useCallback(() => {
isComposingRef.current = true
setIsComposing(true) setIsComposing(true)
}, []) }, [])
const handleCompositionEnd = useCallback(() => { const handleCompositionEnd = useCallback(() => {
isComposingRef.current = false
setIsComposing(false) setIsComposing(false)
// 输入法确认后,需要将当前输入框中的所有字符分散到后续输入框 // 输入法确认后,需要将当前输入框中的所有字符分散到后续输入框
requestAnimationFrame(() => { requestAnimationFrame(() => {