From 315a552f3f75ee8e1b2fac2ab26331410bb92fad Mon Sep 17 00:00:00 2001 From: hansas <13600156+hansas@user.noreply.gitee.com> Date: Sat, 13 Sep 2025 10:14:47 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=A9=BA=E6=A0=BC=E5=88=87?= =?UTF-8?q?=E6=8D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/event.ts | 25 +++++++++++- src/pages/pc/word/components/TypeWord.vue | 47 ++++++++++++++++++++++- src/types/global.d.ts | 6 +++ 3 files changed, 76 insertions(+), 2 deletions(-) diff --git a/src/hooks/event.ts b/src/hooks/event.ts index 75d27fd3..ac425acf 100644 --- a/src/hooks/event.ts +++ b/src/hooks/event.ts @@ -2,6 +2,7 @@ import {onMounted, onUnmounted, watch, onDeactivated} from "vue"; import {emitter, EventKey} from "@/utils/eventBus.ts"; import {useRuntimeStore} from "@/stores/runtime.ts"; import {useSettingStore} from "@/stores/setting.ts"; +import {ShortcutKey} from "@/types/types.ts"; export function useWindowClick(cb: (e: PointerEvent) => void) { onMounted(() => { @@ -53,6 +54,22 @@ export function useStartKeyboardEventListener() { useEventListener('keydown', (e: KeyboardEvent) => { if (!runtimeStore.disableEventListener) { + + // 检查当前单词是否包含空格,如果包含,则空格键应该被视为输入 + if (e.code === 'Space') { + // 获取当前正在输入的单词信息 + const currentWord = window.__CURRENT_WORD_INFO__; + + // 如果当前单词包含空格,且下一个字符应该是空格,则将空格键视为输入 + if (currentWord && + currentWord.word && + currentWord.word.includes(' ') && + currentWord.word[currentWord.input.length] === ' ') { + e.preventDefault(); + return emitter.emit(EventKey.onTyping, e); + } + } + let shortcutKey = getShortcutKey(e) // console.log('shortcutKey', shortcutKey) @@ -71,9 +88,15 @@ export function useStartKeyboardEventListener() { emitter.emit(shortcutEvent, e) } else { //非英文模式下,输入区域的 keyCode 均为 229时, + // 空格键始终应该被转发到onTyping函数,由它来决定是作为输入还是切换单词 + if (e.code === 'Space') { + e.preventDefault(); + return emitter.emit(EventKey.onTyping, e); + } + if (((e.keyCode >= 65 && e.keyCode <= 90) || (e.keyCode >= 48 && e.keyCode <= 57) - || e.code === 'Space' + // 空格键已经在上面处理过了 || e.code === 'Slash' || e.code === 'Quote' || e.code === 'Comma' diff --git a/src/pages/pc/word/components/TypeWord.vue b/src/pages/pc/word/components/TypeWord.vue index 2d1ae530..c801e10c 100644 --- a/src/pages/pc/word/components/TypeWord.vue +++ b/src/pages/pc/word/components/TypeWord.vue @@ -44,6 +44,16 @@ let displayWord = $computed(() => { return props.word.word.slice(input.length + wrong.length) }) +// 在全局对象中存储当前单词信息,以便其他模块可以访问 +function updateCurrentWordInfo() { + window.__CURRENT_WORD_INFO__ = { + word: props.word.word, + input: input, + inputLock: inputLock, + containsSpace: props.word.word.includes(' ') + }; +} + watch(() => props.word, () => { wrong = input = '' wordRepeatCount = 0 @@ -51,11 +61,22 @@ watch(() => props.word, () => { if (settingStore.wordSound) { volumeIconRef?.play(400, true) } + // 更新当前单词信息 + updateCurrentWordInfo(); }, {deep: true}) +// 监听输入变化,更新当前单词信息 +watch(() => input, () => { + updateCurrentWordInfo(); +}) + onMounted(() => { + // 初始化当前单词信息 + updateCurrentWordInfo(); + emitter.on(EventKey.resetWord, () => { wrong = input = '' + updateCurrentWordInfo(); }) emitter.on(EventKey.onTyping, onTyping) @@ -80,7 +101,8 @@ function repeat() { async function onTyping(e: KeyboardEvent) { if (inputLock) { - //如果是锁定状态,说明要么输入太快;要么就是设置了不自动跳转,然后输入完了,当这种情况时,监听空格键,按下切换下一个 + //如果是锁定状态,说明要么输入太快;要么就是设置了不自动跳转,然后输入完了 + //当单词全部输入完成后,空格键用于切换到下一个单词 if (e.code === 'Space' && input.toLowerCase() === props.word.word.toLowerCase()) { return emit('complete') } @@ -88,6 +110,22 @@ async function onTyping(e: KeyboardEvent) { } let letter = e.key inputLock = true + + // 检查当前单词是否包含空格 + const wordContainsSpace = props.word.word.includes(' ') + + // 如果是空格键,需要判断是作为输入还是切换单词 + if (letter === ' ' || e.code === 'Space') { + // 如果当前单词包含空格 + if (wordContainsSpace && props.word.word[input.length] === ' ') { + letter = ' ' + } + // 如果当前单词不包含空格,且已经输入完成,则视为切换单词的信号 + else if (!wordContainsSpace && input.toLowerCase() === props.word.word.toLowerCase()) { + return emit('complete') + } + } + let isTypingRight = false if (settingStore.ignoreCase) { isTypingRight = letter.toLowerCase() === props.word.word[input.length].toLowerCase() @@ -98,6 +136,8 @@ async function onTyping(e: KeyboardEvent) { input += letter wrong = '' playKeyboardAudio() + // 更新当前单词信息 + updateCurrentWordInfo(); } else { emit('wrong') wrong = letter @@ -106,6 +146,8 @@ async function onTyping(e: KeyboardEvent) { await sleep(500) if (settingStore.inputWrongClear) input = '' wrong = '' + // 更新当前单词信息 + updateCurrentWordInfo(); } if (input.toLowerCase() === props.word.word.toLowerCase()) { @@ -140,6 +182,9 @@ function del() { } else { input = input.slice(0, -1) } + + // 更新当前单词信息 + updateCurrentWordInfo(); } const statStore = usePracticeStore() diff --git a/src/types/global.d.ts b/src/types/global.d.ts index ce1821d0..83269e79 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -8,6 +8,12 @@ declare global { interface Window { umami: { track(name: string, data?: any): void + }, + __CURRENT_WORD_INFO__?: { + word: string, + input: string, + inputLock: boolean, + containsSpace: boolean } } }