CSS `scroll-driven-animations` `AnimationController` `API` 与 `JavaScript` 联动

大家好,欢迎来到今天的特别放映厅!今天我们要聊的是CSS Scroll-Driven Animations的隐藏大招 —— AnimationController API,以及它如何与JavaScript擦出激情的火花!

准备好了吗?让我们一起摇滚起来!

1. 啥是AnimationController API?

首先,咱们得明确一点:CSS Scroll-Driven Animations 本身已经足够强大了,可以让动画随着滚动条的移动而翩翩起舞。但是,有时候,我们想要更细粒度的控制,比如:

  • 暂停/恢复动画: 想让动画在某个时刻停下来,或者在用户再次滚动到某个位置时继续播放?
  • 反向播放动画: 想让动画倒着来一遍?(想象一下倒带的电影!)
  • 跳转到动画的某个特定时刻: 想直接跳到动画的中间部分,看看精彩片段?
  • 动态调整动画播放速度: 想让动画忽快忽慢,营造更酷炫的效果?

这时候,AnimationController API 就闪亮登场了!它就像一个遥控器,让你可以用 JavaScript 精确地控制 CSS 滚动驱动动画。

简单来说,AnimationController API 提供了一组方法,让你可以从 JavaScript 中访问和修改 CSS 动画的播放状态。

2. 如何获取AnimationController?

要使用 AnimationController API,首先需要获取到你想控制的动画对应的 AnimationController 对象。方法很简单,使用 Element.getAnimations() 方法,然后找到你想要的动画,再通过 animation.animationController 属性就可以获取到对应的 AnimationController 对象了。

const element = document.querySelector('.my-element');
const animations = element.getAnimations();

// 假设我们知道第一个动画是我们要控制的滚动驱动动画
if (animations.length > 0) {
  const animationController = animations[0].animationController;

  if (animationController) {
    console.log('AnimationController找到了!', animationController);
    // 现在你可以用 animationController 做一些有趣的事情了!
  } else {
    console.warn('这个动画没有AnimationController!');
  }
} else {
  console.warn('这个元素上没有任何动画!');
}

这段代码就像寻宝游戏,先找到宝藏地图(element.getAnimations()),然后根据地图上的线索(动画的索引),最终找到宝藏(animationController)。

3. AnimationController API 的核心方法

有了 AnimationController 对象,我们就可以开始玩转各种控制方法了。下面是一些常用的 API 方法:

方法名 作用 参数 返回值
play() 播放动画 undefined
pause() 暂停动画 undefined
reverse() 反向播放动画(切换播放方向) undefined
seek() 跳转到动画的某个特定时刻(以秒为单位) time (number): 要跳转到的时间点,单位为秒。 undefined
currentTime 获取或设置动画的当前时间(以秒为单位) time (number, 可选): 如果设置,则跳转到指定时间点。如果获取,则返回当前时间。 number
playbackRate 获取或设置动画的播放速度(1 为正常速度,0.5 为半速,2 为双倍速) rate (number, 可选): 如果设置,则改变播放速度。如果获取,则返回当前播放速度。 number

这些方法就像是动画的操控杆,你可以用它们来控制动画的播放、暂停、反向、跳转和速度。

4. 实战演练:一个简单的例子

光说不练假把式,让我们来写一个简单的例子,演示如何使用 AnimationController API 控制一个滚动驱动动画。

HTML:

<div class="container">
  <div class="scroll-container">
    <div class="box">Hello Scroll Driven Animation!</div>
  </div>
  <div class="controls">
    <button id="playButton">Play</button>
    <button id="pauseButton">Pause</button>
    <button id="reverseButton">Reverse</button>
    <input type="range" id="seekSlider" min="0" max="1" step="0.01" value="0">
    <label for="seekSlider">Seek</label>
  </div>
</div>

CSS:

.container {
  width: 300px;
  margin: 50px auto;
  border: 1px solid #ccc;
}

.scroll-container {
  height: 200px;
  overflow-y: scroll;
  padding: 10px;
}

.box {
  height: 500px; /* 确保内容可以滚动 */
  background-color: lightblue;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 20px;

  /* 滚动驱动动画 */
  animation: slideIn 3s linear forwards;
  animation-timeline: view();
  animation-range: entry 20% cover 80%; /* 动画在元素进入视口20%到覆盖80%时触发 */
}

@keyframes slideIn {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(0);
  }
}

.controls {
  padding: 10px;
  display: flex;
  flex-direction: column;
  gap: 5px;
}

JavaScript:

const box = document.querySelector('.box');
const playButton = document.getElementById('playButton');
const pauseButton = document.getElementById('pauseButton');
const reverseButton = document.getElementById('reverseButton');
const seekSlider = document.getElementById('seekSlider');

let animationController;

// 获取 AnimationController
const animations = box.getAnimations();
if (animations.length > 0) {
  animationController = animations[0].animationController;
} else {
  console.warn('没有找到动画!');
}

if (animationController) {
  // 播放按钮
  playButton.addEventListener('click', () => {
    animationController.play();
  });

  // 暂停按钮
  pauseButton.addEventListener('click', () => {
    animationController.pause();
  });

  // 反向按钮
  reverseButton.addEventListener('click', () => {
    animationController.reverse();
  });

  // 滑动条
  seekSlider.addEventListener('input', () => {
    const currentTime = animationController.animation.duration * parseFloat(seekSlider.value);
    animationController.seek(currentTime);
  });

  // 监听滚动事件,更新滑动条
  const scrollContainer = document.querySelector('.scroll-container');
  scrollContainer.addEventListener('scroll', () => {
    const scrollPosition = scrollContainer.scrollTop;
    const maxScroll = scrollContainer.scrollHeight - scrollContainer.clientHeight;
    const progress = scrollPosition / maxScroll;
    // 避免除以0的错误
    if (maxScroll > 0) {
      seekSlider.value = progress;

      // 更新动画的当前时间
      const currentTime = animationController.animation.duration * progress;
      animationController.seek(currentTime);
    }
  });

} else {
  console.warn('AnimationController未找到,请检查动画是否正确设置。');
}

这个例子中,我们创建了一个盒子,它会随着滚动条的滚动从左边滑入。然后,我们用 JavaScript 获取了 AnimationController 对象,并绑定了几个按钮和滑动条,让用户可以控制动画的播放、暂停、反向和跳转。

解释:

  • HTML: 创建了容器、可滚动区域、动画元素(.box)以及控制按钮和滑块。
  • CSS: 设置了基本的样式和关键的滚动驱动动画。 animation-timeline: view(); 让动画基于视口滚动。 animation-range: entry 20% cover 80%; 定义了动画的触发范围。
  • JavaScript:
    • 首先,获取 AnimationController
    • 为播放、暂停和反向按钮添加事件监听器,调用 animationController.play()animationController.pause()animationController.reverse()
    • 为滑块添加事件监听器,当滑块的值改变时,计算对应的动画时间,并使用 animationController.seek() 跳转到该时间点。
    • 监听滚动容器的 scroll 事件,根据滚动位置计算动画进度,并更新滑块和动画的当前时间。

这个例子展示了 AnimationController API 的基本用法,你可以根据自己的需求,灵活地组合这些方法,创造出更复杂的动画效果。

5. 进阶技巧:动态调整播放速度

除了基本的控制方法,AnimationController API 还可以让你动态调整动画的播放速度。这可以用来实现一些有趣的效果,比如:

  • 慢动作: 让动画以很慢的速度播放,突出细节。
  • 快进: 让动画快速播放,跳过不重要的部分。
  • 变速动画: 让动画的速度随着用户的交互而变化,创造更流畅的体验。

要调整动画的播放速度,可以使用 animationController.playbackRate 属性。这个属性的值表示播放速度,1 为正常速度,0.5 为半速,2 为双倍速,以此类推。

// 设置播放速度为 0.5 (半速)
animationController.playbackRate = 0.5;

// 设置播放速度为 2 (双倍速)
animationController.playbackRate = 2;

// 获取当前播放速度
const currentRate = animationController.playbackRate;
console.log('当前播放速度:', currentRate);

你可以根据用户的操作,动态地改变 playbackRate 的值,从而实现变速动画的效果。例如,你可以监听鼠标滚轮事件,根据滚动的方向来调整播放速度:

scrollContainer.addEventListener('wheel', (event) => {
  // 阻止默认的滚动行为
  event.preventDefault();

  // 根据滚动方向调整播放速度
  if (event.deltaY > 0) {
    // 向下滚动,减慢播放速度
    animationController.playbackRate = Math.max(0.1, animationController.playbackRate - 0.1);
  } else {
    // 向上滚动,加快播放速度
    animationController.playbackRate = Math.min(2, animationController.playbackRate + 0.1);
  }

  console.log('当前播放速度:', animationController.playbackRate);
});

这段代码会监听滚动容器的 wheel 事件,当用户向下滚动时,减慢动画的播放速度,当用户向上滚动时,加快动画的播放速度。

6. 注意事项

在使用 AnimationController API 时,需要注意以下几点:

  • 浏览器兼容性: 虽然 AnimationController API 已经得到了主流浏览器的支持,但还是建议在使用前检查一下浏览器的兼容性。可以使用 Can I use 网站来查询浏览器的兼容性信息。
  • 动画类型: AnimationController API 主要用于控制 CSS 滚动驱动动画。对于其他的动画类型,可能需要使用不同的 API。
  • 性能优化: 频繁地操作 AnimationController 对象可能会影响性能。建议尽量减少不必要的更新,并使用 requestAnimationFrame 来优化动画的渲染。
  • 错误处理: 在获取 AnimationController 对象时,要确保动画已经正确加载,并且 animationController 属性存在。如果 animationController 属性为 nullundefined,说明动画没有关联 AnimationController 对象,需要检查动画的设置。

7. 总结

AnimationController API 是 CSS Scroll-Driven Animations 的一个强大的补充,它让你可以用 JavaScript 精确地控制 CSS 动画的播放状态。通过 AnimationController API,你可以实现更复杂的动画效果,并与用户的交互进行更紧密的结合。

希望今天的放映厅能让你对 AnimationController API 有更深入的了解。下次再见!

练习题:

  1. 尝试修改上面的例子,让动画在进入视口时自动播放,离开视口时自动暂停。
  2. 尝试创建一个更复杂的动画,例如,让多个元素同时运动,并使用 AnimationController API 控制它们的播放状态。
  3. 研究一下 AnimationTimeline 接口,看看它和 AnimationController 有什么关系。

祝你编程愉快!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注