如何使用forEach方法让打字效果函数在标题元素数组上依次执行?
解决打字效果依次执行的问题
你的问题在于forEach会同步触发所有的typeEffect调用,每个函数里的setInterval几乎同时启动,所以所有标题的打字效果就撞在一起了。要实现依次执行,我们需要让每个打字效果在上一个完全结束后再开始,这里用Promise配合async/await就能轻松搞定,同时还要先修正原函数里的一个小bug。
步骤1:修复原打字函数的停止逻辑
原代码里的停止条件i === element.length是错误的——一开始元素内容是空的,element.length为0,会直接终止定时器导致打字效果失效。应该改成判断i === str.length,这样当字符全部输出后才清除定时器。
步骤2:将打字函数改为返回Promise
我们把typeEffect改成返回一个Promise,当打字完成时触发resolve,这样就能用await等待它执行结束。
步骤3:用async/await依次执行每个打字效果
不再用forEach同步触发,而是用一个async函数遍历数组,逐个调用typeEffect并等待完成。
修改后的完整代码:
<section id="skills"> <div class="skills-content"> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2></h2> <h2></h2> </div> </section>
// 获取所有h2元素组成的数组 const skillsHeaders = document.querySelectorAll(".skills-content h2"); // 要应用到标题的内容数组 const skillsHeaderContent = [ "HTML", "CSS", "JAVASCRIPT", "SASS", "GIT", "GITHUB", "REACT", ]; /** * 接收元素和字符串作为参数,在指定元素中逐个字符输出给定字符串 * @param {Element} element - 目标元素 * @param {string} str - 要输出的字符串 * @returns {Promise} 打字完成时resolve */ function typeEffect(element, str) { return new Promise((resolve) => { let typedLetters = ""; let i = 0; const interval = setInterval(() => { typedLetters = str.slice(0, i); element.textContent = typedLetters; // 修正停止条件:当i等于字符串长度时,完成打字 if (i === str.length) { clearInterval(interval); resolve(); // 完成后标记Promise为已完成 } i++; }, 120); }); } // 依次执行每个打字效果的函数 async function runTypeEffectsSequentially() { // 遍历数组,只处理有对应内容的元素(避免h2数量多于内容的情况) for (let i = 0; i < skillsHeaderContent.length; i++) { const element = skillsHeaders[i]; if (element) { await typeEffect(element, skillsHeaderContent[i]); } } } // 启动依次打字效果 runTypeEffectsSequentially();
为什么这样有效?
typeEffect现在返回Promise,只有当打字完成(定时器被清除)时才会resolve,相当于给每个打字效果加了“完成标记”。runTypeEffectsSequentially是async函数,里面的for循环会等待每个await typeEffect(...)执行完毕后,才会进入下一次循环,完美实现了逐个标题依次打字的效果。
另外我加了if (element)的判断,因为你的h2元素有9个,但内容数组只有7个,避免出现找不到对应元素的错误。
内容的提问来源于stack exchange,提问作者PeteD
相关产品推荐
相关产品推荐

