JavaScript实现逐字滚动文本效果遇阻,请求技术支援
问题描述
我想要实现这样的效果:在输入框输入内容并点击Go按钮后,输入内容会在runningWords容器中逐字显示,每个字符需从alphabets数组的元素依次滚动,匹配到目标字符后停止,再进行下一个字符的滚动(比如输入“test”时,先滚动到“t”停止,再滚动到“e”停止,以此类推)。
我编写的代码如下:
HTML代码
<html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Project</title> <link rel="stylesheet" href="style.css"> </head> <body> <div class="container"> <div class="runningWords"></div> <div class="inputs"> <input type="text" name="text" id="textInput" value="test" placeholder="Enter String..."> <button onclick="handleClick()">Go...</button> </div> </div> <script src="main.js"></script> </body> </html>
CSS代码
@import url('https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600;700&display=swap'); * { margin: 0; padding: 0; } body { background: #333; font-family: 'Poppins', sans-serif; } .container { display: flex; justify-content: center; align-items: center; width: 100vw; height: 100vh; position: relative; } .container .inputs { display: flex; flex-direction: column; } .container .inputs input { width: 30em; height: 3em; margin-bottom: 1em; border-radius: 0.5em; padding-left: 1em; border: 0.25em solid transparent; transition: all 300ms ease-in-out; } .container .inputs input:hover, .container .inputs input:focus { outline: none; border: 0.25em solid rgb(0, 140, 255); } .container .inputs button { width: 7em; height: 2.5em; margin: auto; border: 1px solid rgb(0, 140, 255); background-color: #333; color: rgb(0, 140, 255); border-radius: 0.5em; transition: all 300ms ease-in-out; cursor: pointer; } .container .inputs button:hover { background-color: rgb(0, 140, 255); color: #333; } .container .runningWords { position: absolute; top: 25%; width: 60%; margin: 0 20%; height: 80px; left: 0; display: flex; justify-content: center; align-items: center; color: rgb(0, 140, 255); font-size: 3em; font-weight: 700; }
JavaScript代码
const alphabets = [' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] const handleClick = async () => { let inputVal = document.getElementById('textInput').value.toLowerCase().split('') if (inputVal.length <= 0) return alert('Please Type something!') for (val in inputVal) { if (alphabets.includes(inputVal[val]) === false) return alert('Use only letters and space') } let inLen = inputVal.length let echTxt = 0 let runningWordsDiv = document.getElementsByClassName('runningWords')[0] do { console.log(echTxt) for (let letter = 0; letter <= alphabets.length; letter++) { setTimeout(() => { if (alphabets[letter] === undefined) return runningWordsDiv.innerHTML = alphabets[letter].toUpperCase() }, 200 * letter); } echTxt++ } while (echTxt < inLen) }
当前代码存在的问题:console.log(echTxt)会瞬间执行到输入内容的长度,之后才开始向runningWords容器中更新内容,无法实现预期的逐字滚动效果。
解决方案
问题根源
setTimeout是异步任务,会被放入事件队列等待执行,而同步的do...while循环会瞬间跑完所有迭代,所有setTimeout任务会在循环结束后才开始依次执行,导致所有字符的滚动任务被同时触发,无法按顺序逐个完成。
修改后的JavaScript代码
const alphabets = [' ', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] // 封装单个字符的滚动逻辑为异步函数 async function scrollToTargetChar(targetChar, displayEl) { for (let letter of alphabets) { displayEl.innerHTML = letter.toUpperCase(); // 等待200ms再进行下一次滚动 await new Promise(resolve => setTimeout(resolve, 200)); // 匹配到目标字符则停止当前字符的滚动 if (letter === targetChar) break; } } const handleClick = async () => { let inputVal = document.getElementById('textInput').value.toLowerCase().split('') if (inputVal.length <= 0) return alert('Please Type something!') for (let val of inputVal) { if (!alphabets.includes(val)) return alert('Use only letters and space') } let runningWordsDiv = document.getElementsByClassName('runningWords')[0] // 逐个处理输入字符,等待当前字符滚动完成再处理下一个 for (let char of inputVal) { await scrollToTargetChar(char, runningWordsDiv); } }
改动说明
- 将单个字符的滚动逻辑封装成
scrollToTargetChar异步函数,用await Promise实现每一步滚动的等待,确保每个字符滚动到目标后再继续。 - 主函数中用
for...of循环遍历输入字符,每个字符都等待scrollToTargetChar完成后再处理下一个,实现逐字滚动的顺序执行。 - 替换原有的
for...in循环(不适合遍历数组),改用for...of更安全规范。 - 移除原有的
do...while和批量触发setTimeout的逻辑,避免异步任务堆积导致的顺序混乱。
修改后即可实现先滚动到第一个目标字符停止,再滚动到第二个目标字符的预期效果。
内容的提问来源于Stack Exchange,提问作者RANTO BERK
相关产品推荐
相关产品推荐

