点击切换内容时,如何先播放消失CSS动画再更新innerHTML、后播放出现动画
淡入淡出失效问题修复方案
核心根因
- 现有JS执行逻辑为同步流程:点击触发后会连续走完「添加disappear类→强制重排→移除disappear类→替换文本→添加appear类」全链路,全程没有给1200ms的淡出动画预留播放窗口,disappear类刚被加上就被移除,动画根本来不及触发。
.disappear样式没有配置forwards动画填充模式,就算动画正常播放,结束后也会立刻跳回原有透明度状态,无法稳定停在全透明的中间态。- 之前尝试setTimeout失效,本质是没有把「替换文本、触发appear动画」的逻辑放进延时回调,仍然是同步执行了全部操作流程。
修复实现逻辑
动画需要按顺序分阶段异步执行,不能一次性同步跑完所有操作:
- 点击触发时,先给容器添加
disappear类,启动旧文本的淡出动画 - 等待淡出动画完整播放完成(时长和CSS配置保持一致),再移除disappear类
- 此时容器处于全透明状态,替换成新的文本、作者内容
- 强制触发一次重排后,给容器添加
appear类,启动新文本的淡入动画
优化细节:给disappear类补上forwards填充模式,让淡出动画结束后稳定保持透明状态,不会出现样式跳变。
进阶优化:如果不想手动匹配JS延时和CSS动画时长,可以在disappear动画触发后,监听容器的
animationend事件,等fadeOut动画真正执行完成后再触发后续逻辑,避免两处时长配置不一致导致的动画错位问题。
修正后的代码
调整后的CSS
.quote-container { opacity: 0; } .appear { opacity: 0; animation: fadeIn 1200ms ease-in forwards; } /* 补充forwards填充模式,动画结束保持终态 */ .disappear { animation: fadeOut 1200ms ease-in forwards; } @keyframes fadeIn { from { opacity: 0; } to { opacity: 1; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } }
调整后的JavaScript
// 原有quotes数据、变量定义逻辑保持不变 let quotes = []; let currentQuote = ''; let currentAuthor = ''; let index = 0; // 提取动画时长常量,和CSS配置保持同步,后续调整时长无需多处修改 const FADE_ANIMATION_DURATION = 1200; let pickARandomQuote = () => { // 随机获取索引、文本内容的逻辑保持不变 index = Math.floor(Math.random() * quotes.length); currentQuote = quotes[index].quote; currentAuthor = quotes[index].author; const quoteContainer = document.getElementById("quote-container"); const textEl = document.getElementById("text"); const authorEl = document.getElementById("author"); // 第一步:触发旧文本消失动画 quoteContainer.classList.remove("appear"); quoteContainer.classList.add("disappear"); // 第二步:等待消失动画播放完成,再执行后续内容替换、新动画触发 setTimeout(() => { quoteContainer.classList.remove("disappear"); // 替换为新的引用内容 textEl.innerHTML = currentQuote; authorEl.innerHTML = "- " + currentAuthor; // 强制重排,确保新的appear动画能正常从头触发 void quoteContainer.offsetWidth; quoteContainer.classList.add("appear"); }, FADE_ANIMATION_DURATION); return { quote: currentQuote, author: currentAuthor }; }; // 页面初始化绑定逻辑保持不变 document.addEventListener("DOMContentLoaded", pickARandomQuote); const newQuoteBtn = document.getElementById("new-quote"); if (newQuoteBtn) { newQuoteBtn.addEventListener("click", pickARandomQuote); }
内容的提问来源于stack exchange,提问作者BiT4000
相关产品推荐
相关产品推荐

