如何修改lastElementSibling的ClassName?打字游戏类切换异常求助
问题分析与解决方案
项目概述
我有一个id为wordsContainer的div,内部包含多个div(每个对应一个单词),每个单词被拆分为多个<span>标签(每个span承载一个字母),用于实现判断输入字母对错的简易打字游戏。
问题描述
在addEventListener的keydown事件处理函数中,尝试根据输入切换元素类名时出现两个问题:
- 例如单词"hello",前几个字母能正常响应,但到字母"o"时无法切换类名;
- 按下空格可切换到下一个单词,但下一个单词的span标签无任何响应,仅空格能切换单词。
尝试方案
目前使用nextSibling方法实现,也曾尝试querySelector(classname),但无法识别单词结尾(所有字母初始为"letter"类,按键后修改类名以定位下一个字母)。
当前代码
function addClass(element, name){ // adds Class element.className = ''+name; } function removeClass(element , name){ // Removes class element.className= element.className.replace(name, ' '); } let wordSibling = wordsContainer.firstElementChild; let letterSibling = wordSibling.firstChild; addClass(wordSibling, "currentWord") addClass(letterSibling, "currentLetter" ) document.addEventListener("keydown", function(e){ const typedKey = e.key; const expected = document.querySelector(".currentLetter").innerHTML; console.log({expected , typedKey}); if ( letterSibling.nextSibling){ addClass(letterSibling, "currentLetter") letterSibling = letterSibling.nextSibling; addClass(letterSibling, "currentLetter") removeClass(letterSibling.previousSibling, "currentLetter") addClass(letterSibling.previousSibling, expected===typedKey? "correct": "incorrect") }else { if (typedKey === " "){ wordSibling= wordSibling.nextSibling; wordSibling.previousSibling.lastChild.className = expected===typedKey? "correct": "incorrect"; letterSibling = wordSibling.firstChild addClass(letterSibling, "currentletter") addClass(wordSibling, "currentWord") removeClass(wordSibling.previousSibling, "currentWord")} } })
问题根源与修复方案
1. 类名大小写不一致
切换到下一个单词时,代码里写的是addClass(letterSibling, "currentletter")(小写l),但之前的类名是currentLetter(大写L),导致后续querySelector(".currentLetter")找不到目标元素,下一个单词的字母完全无法响应输入。
2. 最后一个字母的逻辑错误
当前代码中,当处理到单词的最后一个字母时,letterSibling.nextSibling为null,会直接进入else分支,但else分支只有按空格才会处理,导致最后一个字母的对错状态无法被标记,且无法触发后续的输入响应。
3. 字母切换顺序错误
原代码中先切换letterSibling到下一个,再给前一个字母标记对错,逻辑顺序颠倒,应该先判断当前输入是否正确,标记当前字母的状态,再切换到下一个字母。
修正后的代码
function addClass(element, name) { // 保留基础类名,避免覆盖原有样式 element.className = `letter ${name}`; } function removeClass(element, name) { // 更严谨的类名移除方式 element.classList.remove(name); } let wordSibling = wordsContainer.firstElementChild; let letterSibling = wordSibling.firstElementChild; // 用firstElementChild避免文本节点干扰 addClass(wordSibling, "currentWord"); addClass(letterSibling, "currentLetter"); document.addEventListener("keydown", function(e) { const typedKey = e.key; const expected = letterSibling.textContent; // 直接从当前字母元素获取,无需重复查询 // 处理字母输入 if (typedKey !== " ") { // 先标记当前字母的对错状态 addClass(letterSibling, typedKey === expected ? "correct" : "incorrect"); // 如果有下一个字母,切换到下一个 if (letterSibling.nextElementSibling) { letterSibling = letterSibling.nextElementSibling; addClass(letterSibling, "currentLetter"); } } // 处理空格切换单词(仅当当前单词的最后一个字母已处理) if (typedKey === " " && !letterSibling.nextElementSibling) { // 切换到下一个单词(判断是否存在下一个单词) if (wordSibling.nextElementSibling) { removeClass(wordSibling, "currentWord"); wordSibling = wordSibling.nextElementSibling; addClass(wordSibling, "currentWord"); letterSibling = wordSibling.firstElementChild; addClass(letterSibling, "currentLetter"); } } });
额外优化点
- 使用
firstElementChild和nextElementSibling替代firstChild和nextSibling,避免HTML中的空白文本节点干扰元素定位; - 改进
addClass函数,保留基础的letter类名,避免覆盖原有样式; - 用
classList.remove替代字符串替换,更安全地移除类名; - 直接从当前
letterSibling获取预期字母,无需重复使用querySelector,提升性能。
内容的提问来源于stack exchange,提问作者Marcian
相关产品推荐
相关产品推荐

