JavaScript步骤进度条仅首次点击过渡动画正常问题求助
问题解决:步骤进度条描述切换动画失效及优化方案
问题原因
动画仅首次生效的核心原因是:动画类(leave-left/leave-right/enter-left/enter-right)在第一次执行后未被彻底移除。第二次点击步骤时,目标元素仍保留这些类名,浏览器不会重复触发相同的动画规则,导致过渡效果消失。
你手动移除类的思路是正确的,只需确保类的移除与重新添加之间存在DOM更新间隙,让浏览器识别状态变化以重新触发动画。
解决方案
在updateProgress函数中,先清除所有动画类,再通过requestAnimationFrame延迟添加新动画类,确保DOM完成状态更新后触发动画:
const updateProgress = () => { // 清除所有动画类 texts.forEach(text => { text.classList.remove("leave-left", "leave-right", "enter-left", "enter-right"); }); // 更新步骤激活状态 steps.forEach((step, i) => { step.classList.toggle("active", i < active); }); // 更新文本激活状态 texts.forEach((text, i) => { text.classList.toggle("active", (i + 1) === active); }); // 延迟添加动画类,确保DOM状态更新完成 requestAnimationFrame(() => { if (!previous) return; // 首次加载无previous,跳过动画 const prevText = texts[previous - 1]; const currentText = texts[active - 1]; if (previous > active) { prevText.classList.add("leave-right"); currentText.classList.add("enter-left"); } else if (previous < active) { prevText.classList.add("leave-left"); currentText.classList.add("enter-right"); } }); };
整体代码优化方案
1. 简化事件绑定(消除重复代码)
无需为每个步骤单独绑定点击事件,通过循环遍历steps集合,利用data-index属性存储步骤索引:
修改HTML:
<ul id="progress-bar"> <li class="step step-1 active" data-index="1">One</li> <li class="step step-2" data-index="2">Two</li> <li class="step step-3" data-index="3">Three</li> <li class="step step-4" data-index="4">Four</li> <li class="step step-5" data-index="5">Five</li> </ul>
统一绑定事件:
steps.forEach(step => { step.addEventListener("click", () => { previous = active; active = parseInt(step.dataset.index); updateProgress(); }); });
2. 简化激活状态判断
用classList.toggle()替代复杂条件判断,代码更简洁:
// 更新步骤激活状态 steps.forEach((step, i) => { step.classList.toggle("active", i < active); }); // 更新文本激活状态 texts.forEach((text, i) => { text.classList.toggle("active", (i + 1) === active); });
3. 优化动画逻辑
避免重复遍历texts集合,直接通过索引获取上一个和当前文本元素,减少不必要的循环:
// 延迟触发动画 requestAnimationFrame(() => { if (!previous) return; const prevText = texts[previous - 1]; const currentText = texts[active - 1]; if (previous > active) { prevText.classList.add("leave-right"); currentText.classList.add("enter-left"); } else if (previous < active) { prevText.classList.add("leave-left"); currentText.classList.add("enter-right"); } });
4. 修复CSS冗余过渡属性
补充缺失的过渡时长,确保过渡效果明确:
#progress-bar li.active:before { border-color: #b78e15; background-color: #b78e15; transition: all .8s; /* 补充时长,与hover效果保持一致 */ } #progress-bar li.active:after { background-color: #b78e15; transition: all .8s; /* 补充时长 */ }
完整优化后的JS代码
const steps = document.querySelectorAll(".step"); const texts = document.querySelectorAll(".progress-text"); let active = 1; let previous; const updateProgress = () => { // 清除所有动画类 texts.forEach(text => { text.classList.remove("leave-left", "leave-right", "enter-left", "enter-right"); }); // 更新步骤激活状态 steps.forEach((step, i) => { step.classList.toggle("active", i < active); }); // 更新文本激活状态 texts.forEach((text, i) => { text.classList.toggle("active", (i + 1) === active); }); // 延迟触发动画 requestAnimationFrame(() => { if (!previous) return; const prevText = texts[previous - 1]; const currentText = texts[active - 1]; if (previous > active) { prevText.classList.add("leave-right"); currentText.classList.add("enter-left"); } else if (previous < active) { prevText.classList.add("leave-left"); currentText.classList.add("enter-right"); } }); }; // 统一绑定点击事件 steps.forEach(step => { step.addEventListener("click", () => { previous = active; active = parseInt(step.dataset.index); updateProgress(); }); });
内容的提问来源于stack exchange,提问作者uthy_97
相关产品推荐
相关产品推荐

