如何控制 一个动画完成再执行下一个动画

一、纯 CSS 方案(利用 animationend 事件)

通过监听动画结束事件 animationend,触发下一个动画。

<div class="box" id="box1">动画1</div>
<div class="box" id="box2">动画2</div>
.box {
  width: 100px;
  height: 100px;
  opacity: 0;
}

/* 初始隐藏 */
#box1 { background: red; }
#box2 { background: blue; }

/* 动画定义 */
@keyframes fadeIn {
  from { opacity: 0; }
  to { opacity: 1; }
}
const box1 = document.getElementById('box1');
const box2 = document.getElementById('box2');

// 监听第一个动画结束
box1.addEventListener('animationend', () => {
  box2.style.animation = 'fadeIn 1s forwards'; // 触发第二个动画
});

// 启动第一个动画
box1.style.animation = 'fadeIn 1s forwards';

二、Web Animations API(现代浏览器)

利用 finished Promise 控制动画队列。

const box1 = document.getElementById('box1');
const box2 = document.getElementById('box2');

// 定义动画
const animate1 = box1.animate(
  [{ opacity: 0 }, { opacity: 1 }],
  { duration: 1000 }
);

// 第一个动画完成后触发第二个
animate1.finished.then(() => {
  box2.animate(
    [{ opacity: 0 }, { opacity: 1 }],
    { duration: 1000 }
  );
});

三、CSS Transition + Promise(精确控制)

将 CSS 过渡包装成 Promise。

function waitForTransition(element) {
  return new Promise(resolve => {
    element.addEventListener('transitionend', resolve, { once: true });
  });
}

// 使用示例
const box = document.querySelector('.box');

// 第一个动画
box.style.transform = 'translateX(200px)';
box.style.transition = 'transform 1s';

waitForTransition(box).then(() => {
  // 第二个动画
  box.style.transform = 'translateY(200px)';
});

四、Async/Await 链式调用

用现代 JavaScript 语法组织动画队列。

async function runAnimations() {
  const box1 = document.getElementById('box1');
  const box2 = document.getElementById('box2');

  // 第一个动画
  await box1.animate([{ opacity: 0 }, { opacity: 1 }], 1000).finished;
  
  // 第二个动画
  await box2.animate([{ opacity: 0 }, { opacity: 1 }], 1000).finished;

  // 更多动画...
}

runAnimations();

五、GSAP 动画库(专业级解决方案)

使用业界标杆动画库 GSAP 的时序控制。

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.12.2/gsap.min.js"></script>

<div class="box" id="box1"></div>
<div class="box" id="box2"></div>
// 创建时间线
const tl = gsap.timeline();

// 链式调用动画
tl.to("#box1", { duration: 1, x: 200 })
  .to("#box2", { duration: 1, y: 200 }, "+=0.5"); // 延迟 0.5 秒执行
image.png

最佳实践
简单动画序列 → 纯 CSS + animationend 事件
现代浏览器项目 → Web Animations API + async/await
企业级复杂动画 → GSAP 时间线控制
关键点:避免使用 setTimeout 控制动画时序(帧率不稳定),优先使用基于事件或 Promise 的方案。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容