-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
292 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,173 @@ | ||
<script setup lang="ts"> | ||
import { ref, onMounted, reactive, nextTick, watch } from 'vue'; | ||
import { KEY_CODE_ENUM } from '@/config/key'; | ||
type SentenceArrItem = { | ||
id: number; | ||
word: string; | ||
isInput: boolean; | ||
isWrong: boolean; | ||
}; | ||
const whiteList = ['”']; // 白名单 | ||
const inputAreaRef = ref<HTMLElement | null>(null); | ||
const props = defineProps<{ | ||
sentence: string; | ||
}>(); | ||
const state = reactive({ | ||
isComposing: false, | ||
inputText: '', | ||
sentenceArr: [] as SentenceArrItem[] | ||
}); | ||
onMounted(async () => { | ||
await nextTick(); | ||
if (!inputAreaRef.value) return; | ||
inputAreaRef.value.focus(); | ||
}); | ||
watch( | ||
() => props.sentence, | ||
(val) => { | ||
state.inputText = ''; | ||
if (inputAreaRef.value) { | ||
inputAreaRef.value.innerHTML = ''; | ||
inputAreaRef.value.focus(); | ||
} | ||
state.sentenceArr = val.split('').map((item, index) => { | ||
return { | ||
id: index, | ||
word: item, | ||
isInput: false, | ||
isWrong: false | ||
}; | ||
}); | ||
}, | ||
{ | ||
immediate: true | ||
} | ||
); | ||
watch( | ||
() => state.inputText, | ||
(newVal) => { | ||
const inputTextArr = newVal.split(''); | ||
state.sentenceArr.forEach((item, index) => { | ||
item.isInput = false; | ||
item.isWrong = false; | ||
if (inputTextArr[index]) { | ||
item.isInput = true; | ||
item.isWrong = item.word !== inputTextArr[index]; | ||
if (whiteList.includes(inputTextArr[index])) { | ||
item.isInput = item.word === inputTextArr[index]; | ||
item.isWrong = false; | ||
} | ||
} | ||
}); | ||
console.log('----------', 'state.sentenceArr', state.sentenceArr, '----------cyy log'); | ||
} | ||
); | ||
function handlerInput(text: string) { | ||
console.log('----------', 'text', text, '----------cyy log'); | ||
state.inputText = text; | ||
} | ||
function pasteEvent(e: ClipboardEvent) { | ||
e.preventDefault(); | ||
} | ||
function keyDownEvent(e: KeyboardEvent) { | ||
if (e.code === KEY_CODE_ENUM['ENTER'] || e.code === KEY_CODE_ENUM['SPACE']) { | ||
e.preventDefault(); | ||
} | ||
} | ||
function inputEvent(e: Event) { | ||
const input = e.target as HTMLElement; | ||
if (!state.isComposing) { | ||
handlerInput(input?.innerText); | ||
} | ||
} | ||
function compositionStartEvent() { | ||
state.isComposing = true; | ||
} | ||
function compositionUpdateEvent() { | ||
state.isComposing = true; | ||
} | ||
function compositionEndEvent(e: CompositionEvent) { | ||
state.isComposing = false; | ||
const input = e.target as HTMLElement; | ||
const text = input?.innerText; | ||
if (text.length !== state.inputText.length) { | ||
handlerInput(text); | ||
} | ||
} | ||
</script> | ||
|
||
<template> | ||
<div class="y-word-input"> | ||
<div class="y-word-input__sentence"> | ||
<span | ||
v-for="item in state.sentenceArr" | ||
:class="[item.isWrong ? 'is-wrong' : '', item.isInput ? 'is-input' : '']" | ||
:key="item.id" | ||
>{{ item.word }}</span | ||
> | ||
</div> | ||
<div | ||
ref="inputAreaRef" | ||
@paste="pasteEvent" | ||
@keydown="keyDownEvent" | ||
@input="inputEvent" | ||
@compositionstart="compositionStartEvent" | ||
@compositionupdate="compositionUpdateEvent" | ||
@compositionend="compositionEndEvent" | ||
class="y-word-input__input-area" | ||
contenteditable="true" | ||
></div> | ||
</div> | ||
</template> | ||
|
||
<style lang="scss"> | ||
.y-word-input { | ||
position: relative; | ||
user-select: none; | ||
} | ||
.y-word-input__sentence { | ||
line-height: 70px; | ||
user-select: none; | ||
color: $gray-04; | ||
.is-input { | ||
color: $gray-06; | ||
} | ||
.is-wrong { | ||
color: $main-red; | ||
} | ||
} | ||
.y-word-input__input-area { | ||
position: absolute; | ||
user-select: none; | ||
top: 30px; | ||
line-height: 70px; | ||
display: inline-block; | ||
width: 100%; | ||
color: $gray-08; | ||
transition: all 0.3s; | ||
outline: 0; | ||
&:after { | ||
content: ''; | ||
position: absolute; | ||
display: block; | ||
width: 100%; | ||
height: 1px; | ||
bottom: 20px; | ||
background: $gray-06; | ||
} | ||
&:hover, | ||
&:focus { | ||
&:after { | ||
background: $main-color-hover; | ||
} | ||
} | ||
} | ||
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,14 @@ | ||
{ | ||
"title": "背影节选", | ||
"author": "朱自清", | ||
"content": "我说道,“爸爸,你走吧。”他望车外看了看,说,“我买几个橘子去。你就在此地,不要走动。”我看那边月台的栅栏外有几个卖东西的等着顾客。走到那边月台,须穿过铁道,须跳下去又爬上去。父亲是一个胖子,走过去自然要费事些。我本来要去的,他不肯,只好让他去。我看见他戴着黑布小帽,穿着黑布大马褂,深青布棉袍,蹒跚地走到铁道边,慢慢探身下去,尚不大难。可是他穿过铁道,要爬上那边月台,就不容易了。他用两手攀着上面,两脚再向上缩;他肥胖的身子向左微倾,显出努力的样子。这时我看见他的背影,我的泪很快地流下来了。我赶紧拭干了泪,怕他看见,也怕别人看见。我再向外看时,他已抱了朱红的橘子望回走了。过铁道时,他先将橘子散放在地上,自己慢慢爬下,再抱起橘子走。到这边时,我赶紧去搀他。他和我走到车上,将橘子一股脑儿放在我的皮大衣上。于是扑扑衣上的泥土,心里很轻松似的,过一会说,“我走了;到那边来信!”我望着他走出去。他走了几步,回过头看见我,说,“进去吧,里边没人。”等他的背影混入来来往往的人里,再找不着了,我便进来坐下,我的眼泪又来了。" | ||
} | ||
[ | ||
{ | ||
"title": "背影节选", | ||
"author": "朱自清", | ||
"type": "散文", | ||
"content": "我说道,“爸爸,你走吧。”他望车外看了看,说,“我买几个橘子去。你就在此地,不要走动。”我看那边月台的栅栏外有几个卖东西的等着顾客。走到那边月台,须穿过铁道,须跳下去又爬上去。父亲是一个胖子,走过去自然要费事些。我本来要去的,他不肯,只好让他去。我看见他戴着黑布小帽,穿着黑布大马褂,深青布棉袍,蹒跚地走到铁道边,慢慢探身下去,尚不大难。可是他穿过铁道,要爬上那边月台,就不容易了。他用两手攀着上面,两脚再向上缩;他肥胖的身子向左微倾,显出努力的样子。这时我看见他的背影,我的泪很快地流下来了。我赶紧拭干了泪,怕他看见,也怕别人看见。我再向外看时,他已抱了朱红的橘子望回走了。过铁道时,他先将橘子散放在地上,自己慢慢爬下,再抱起橘子走。到这边时,我赶紧去搀他。他和我走到车上,将橘子一股脑儿放在我的皮大衣上。于是扑扑衣上的泥土,心里很轻松似的,过一会说,“我走了;到那边来信!”我望着他走出去。他走了几步,回过头看见我,说,“进去吧,里边没人。”等他的背影混入来来往往的人里,再找不着了,我便进来坐下,我的眼泪又来了。" | ||
}, | ||
{ | ||
"title": "关雎", | ||
"author": "佚名", | ||
"type": "诗歌", | ||
"content": "关关雎鸠,在河之洲。窈窕淑女,君子好逑。参差荇菜,左右流之。窈窕淑女,寤寐求之。求之不得,寤寐思服。悠哉悠哉,辗转反侧。参差荇菜,左右采之。窈窕淑女,琴瑟友之。参差荇菜,左右芼之。窈窕淑女,钟鼓乐之。" | ||
} | ||
] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
let lastIndex: number = -1; | ||
|
||
export function getRandomNonRepeatingElement<T>(arr: T[]): T | null { | ||
// 如果数组为空,返回 null 或者适当的值 | ||
if (arr.length === 0) { | ||
return null; | ||
} | ||
|
||
// 如果数组中只有一个元素,直接返回该元素 | ||
if (arr.length === 1) { | ||
return arr[0]; | ||
} | ||
|
||
let randomIndex: number = lastIndex; | ||
|
||
// 确保每次随机选择的索引与上次不同 | ||
while (randomIndex === lastIndex) { | ||
randomIndex = Math.floor(Math.random() * arr.length); | ||
} | ||
|
||
lastIndex = randomIndex; | ||
return arr[randomIndex]; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters