fix(练习): 修复输入法组合期间焦点跳转导致字母分散问题

- 组合输入期间禁止useEffect自动聚焦到下一个空输入框
- onCompositionEnd直接传入index和value,不再扫描数组查找
- 确保拼音字母留在同一输入框,确认后正确分散成中文

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

Co-Authored-By: HAPI <noreply@hapi.run>
This commit is contained in:
ittoview
2026-03-02 01:34:31 +00:00
parent b4dcd565d6
commit 5d97c70e06
2 changed files with 32 additions and 27 deletions

View File

@@ -11,8 +11,8 @@ interface InputAreaProps {
inputLocked: boolean
lastErrorTimestamp: number | null
onInputChange: (newInput: string[]) => void
onCompositionStart: () => void
onCompositionEnd: () => void
onCompositionStart: (index: number) => void
onCompositionEnd: (index: number, value: string) => void
onPaste: (e: React.ClipboardEvent) => void
}
@@ -31,11 +31,12 @@ export function InputArea({
// 自动聚焦到第一个空输入框
useEffect(() => {
if (isComposing || inputLocked) return
const firstEmptyIndex = userInput.findIndex((char) => !char)
if (firstEmptyIndex !== -1 && inputRefs.current[firstEmptyIndex]) {
inputRefs.current[firstEmptyIndex]?.focus()
}
}, [userInput])
}, [userInput, isComposing, inputLocked])
const handleCharInput = (
index: number,
@@ -137,8 +138,10 @@ export function InputArea({
value={char}
onChange={(e) => handleCharInput(index, e)}
onKeyDown={(e) => handleKeyDown(index, e)}
onCompositionStart={onCompositionStart}
onCompositionEnd={onCompositionEnd}
onCompositionStart={() => onCompositionStart(index)}
onCompositionEnd={(e) =>
onCompositionEnd(index, e.currentTarget.value)
}
onPaste={onPaste}
disabled={inputLocked}
className={clsx(

View File

@@ -207,39 +207,41 @@ export default function ProcessPracticePage() {
)
// 输入法状态管理
const handleCompositionStart = useCallback(() => {
const handleCompositionStart = useCallback((_index: number) => {
isComposingRef.current = true
setIsComposing(true)
}, [])
const handleCompositionEnd = useCallback(() => {
isComposingRef.current = false
setIsComposing(false)
// 输入法确认后,需要将当前输入框中的所有字符分散到后续输入框
requestAnimationFrame(() => {
const currentInput = latestInputRef.current
// 找到第一个有内容且长度>1的输入框(输入法组合的结果)
const composedIndex = currentInput.findIndex((char) => char.length > 1)
if (composedIndex !== -1) {
const composedText = currentInput[composedIndex]
const chars = composedText.split('')
const handleCompositionEnd = useCallback(
(index: number, value: string) => {
isComposingRef.current = false
setIsComposing(false)
// 输入法确认后,需要将当前输入框中的所有字符分散到后续输入框
requestAnimationFrame(() => {
const currentInput = latestInputRef.current
const composedText = value
const newInput = [...currentInput]
// 将组合的字符分散到后续输入框
for (let i = 0; i < chars.length && composedIndex + i < newInput.length; i++) {
newInput[composedIndex + i] = chars[i]
if (composedText) {
const chars = composedText.split('')
for (
let i = 0;
i < chars.length && index + i < newInput.length;
i++
) {
newInput[index + i] = chars[i]
}
} else {
newInput[index] = ''
}
latestInputRef.current = newInput
setUserInput(newInput)
validateInput(newInput)
} else {
// 没有多字符组合,直接验证当前输入
validateInput(currentInput)
}
})
}, [validateInput])
})
},
[validateInput]
)
// 批量粘贴处理
const handlePaste = useCallback(