各位观众老爷,大家好!今天咱们来聊聊前端动画界的一对新秀——CSS Web Animations API(WAAPI)中的KeyframeEffect
和AnimationTimeline
。别怕,听名字挺吓人,其实它们能让你用JavaScript控制CSS动画,玩出更多花样,而且比直接操作CSS类名、过渡啥的更强大、更灵活。
WAAPI:动画界的瑞士军刀
首先,咱得明确一下WAAPI是个啥。简单来说,它是一套JavaScript API,允许你通过代码创建、控制和操作Web动画。你可以把它想象成一把瑞士军刀,各种动画需求都能用它来解决。而KeyframeEffect
和AnimationTimeline
就是这把军刀上的两把常用刀具。
KeyframeEffect
:动画的剧本
KeyframeEffect
就像动画的剧本,它描述了动画在不同时间点的状态。你可以在剧本里指定元素在什么时候应该是什么样子,比如位置、大小、颜色等等。
语法:
new KeyframeEffect(
element, // 要应用动画的元素
keyframes, // 关键帧数组或关键帧对象
options // 动画选项
);
element
: 动画应用的目标元素,HTMLElement 对象。keyframes
: 一个数组或对象,定义动画的关键帧。- 数组形式:每个元素都是一个对象,包含CSS属性和对应的值,表示在该时间点的状态。
- 对象形式:以CSS属性为键,值为包含值的数组,数组的每个元素对应一个关键帧的值。
options
: 一个对象,定义动画的选项,例如:duration
: 动画持续时间,单位毫秒。easing
: 缓动函数,例如linear
,ease
,ease-in
,ease-out
,ease-in-out
。delay
: 动画延迟开始的时间,单位毫秒。iterations
: 动画重复次数,Infinity
表示无限重复。direction
: 动画播放方向,例如normal
,reverse
,alternate
,alternate-reverse
。fill
: 动画在开始和结束时的填充模式,例如none
,forwards
,backwards
,both
。
举个栗子:
<div id="box" style="width: 100px; height: 100px; background-color: red; position: relative;"></div>
<script>
const box = document.getElementById('box');
// 关键帧数组
const keyframes = [
{ transform: 'translateX(0)' },
{ transform: 'translateX(200px)' },
{ transform: 'translateX(0)' }
];
// 动画选项
const options = {
duration: 2000, // 2秒
easing: 'ease-in-out', // 缓动函数
iterations: Infinity // 无限循环
};
// 创建 KeyframeEffect
const keyframeEffect = new KeyframeEffect(box, keyframes, options);
// 创建 Animation 对象 (后面会讲)
const animation = new Animation(keyframeEffect, document.timeline);
// 播放动画
animation.play();
</script>
这个例子创建了一个红色的方块,它会在水平方向上来回移动,持续2秒,无限循环,并且使用了缓动函数。
AnimationTimeline
:动画的时间线
AnimationTimeline
就像电影的时间轴,它管理着动画的播放进度。默认情况下,浏览器提供了一个文档级的AnimationTimeline
,可以通过document.timeline
访问。 你也可以创建自定义的AnimationTimeline
,但这种情况比较少见。
document.timeline
提供了当前文档的全局动画时间。它主要用于创建和管理动画。
currentTime
: 当前动画的时间,以毫秒为单位。getAnimations()
: 返回一个包含所有与此时间线关联的 Animation 对象的数组。
// 获取当前时间
const currentTime = document.timeline.currentTime;
console.log(currentTime);
// 获取所有与时间线关联的动画
const animations = document.timeline.getAnimations();
console.log(animations);
Animation
:把剧本搬上舞台
有了剧本(KeyframeEffect
)和时间线(AnimationTimeline
),还需要一个导演把剧本搬上舞台,这个导演就是Animation
对象。Animation
对象负责将KeyframeEffect
应用到指定的元素上,并按照时间线的进度来控制动画的播放。
语法:
new Animation(
effect, // KeyframeEffect 对象
timeline // AnimationTimeline 对象
);
effect
: 要播放的 KeyframeEffect 对象。timeline
: AnimationTimeline 对象,指定动画的时间线。如果省略,则使用document.timeline
。
Animation
对象提供了一些方法来控制动画的播放:
play()
: 开始或恢复播放动画。pause()
: 暂停动画。reverse()
: 反向播放动画。cancel()
: 取消动画,将元素恢复到动画开始前的状态。finish()
: 立即将动画跳转到结束状态。updatePlaybackRate(playbackRate)
: 设置动画的播放速度,playbackRate
为 1 表示正常速度,0.5 表示慢速,2 表示快速,负数表示反向播放。currentTime
: 获取或设置动画的当前时间。playbackRate
: 获取或设置动画的播放速度。onfinish
: 动画完成时触发的事件。oncancel
: 动画取消时触发的事件。
把之前的例子补全:
<div id="box" style="width: 100px; height: 100px; background-color: red; position: relative;"></div>
<script>
const box = document.getElementById('box');
// 关键帧数组
const keyframes = [
{ transform: 'translateX(0)' },
{ transform: 'translateX(200px)' },
{ transform: 'translateX(0)' }
];
// 动画选项
const options = {
duration: 2000, // 2秒
easing: 'ease-in-out', // 缓动函数
iterations: Infinity // 无限循环
};
// 创建 KeyframeEffect
const keyframeEffect = new KeyframeEffect(box, keyframes, options);
// 创建 Animation 对象
const animation = new Animation(keyframeEffect, document.timeline);
// 播放动画
animation.play();
// 暂停动画(5秒后)
setTimeout(() => {
animation.pause();
console.log("动画暂停");
// 恢复动画(2秒后)
setTimeout(() => {
animation.play();
console.log("动画恢复");
}, 2000);
}, 5000);
// 动画完成时触发的事件
animation.onfinish = () => {
console.log("动画完成");
};
</script>
这个例子演示了如何使用 play()
, pause()
, 和 onfinish
事件。
KeyframeEffect
和 AnimationTimeline
的关系
简单来说,KeyframeEffect
定义了动画的内容,AnimationTimeline
定义了动画的时间轴,而 Animation
对象将两者结合起来,控制动画的播放。KeyframeEffect
描述了“动画应该怎么动”,AnimationTimeline
描述了“动画在什么时候动”,Animation
对象则负责将两者连接起来,让动画真正跑起来。
更高级的用法:自定义 AnimationTimeline
虽然默认的 document.timeline
已经足够用了,但在某些特殊情况下,你可能需要自定义 AnimationTimeline
。例如,你想让动画的播放速度与用户的滚动距离相关联,这时就需要自己创建一个时间线,并根据滚动距离来更新时间线的 currentTime
。
创建自定义的时间轴 (Experimental):
const myTimeline = new AnimationTimeline();
实际应用场景
- 滚动动画(Scroll-Driven Animations): 根据页面滚动的位置来控制动画的进度,实现视差滚动效果或其他复杂的滚动交互。
- 手势动画(Gesture-Driven Animations): 根据用户的手势操作来控制动画的播放,例如拖拽、滑动等。
- 复杂的动画编排: 使用 WAAPI 可以更灵活地编排多个动画,实现更复杂的动画效果。
- 状态驱动的动画: 根据应用的状态来触发不同的动画,例如加载动画、过渡动画等。
案例:滚动驱动的进度条
<!DOCTYPE html>
<html>
<head>
<title>滚动驱动的进度条</title>
<style>
body {
height: 2000px; /* 模拟长页面 */
}
#progress-bar {
position: fixed;
top: 0;
left: 0;
width: 0%;
height: 5px;
background-color: blue;
z-index: 1000;
}
</style>
</head>
<body>
<div id="progress-bar"></div>
<script>
const progressBar = document.getElementById('progress-bar');
// 获取文档的总高度
const totalHeight = document.documentElement.scrollHeight - document.documentElement.clientHeight;
// 定义关键帧
const keyframes = [
{ width: '0%' },
{ width: '100%' }
];
// 定义动画选项
const options = {
duration: 1, // duration 不重要,因为我们会手动控制
fill: 'forwards'
};
// 创建 KeyframeEffect
const keyframeEffect = new KeyframeEffect(progressBar, keyframes, options);
// 创建 Animation 对象
const animation = new Animation(keyframeEffect, document.timeline);
// 手动暂停动画
animation.pause();
// 监听滚动事件
window.addEventListener('scroll', () => {
// 计算滚动百分比
const scrollPercentage = (document.documentElement.scrollTop / totalHeight) * 100;
// 设置动画的当前时间,注意单位是秒
animation.currentTime = (scrollPercentage / 100);
});
</script>
</body>
</html>
这个例子创建了一个固定在页面顶部的蓝色进度条,当页面滚动时,进度条的宽度会根据滚动距离来更新,从而显示当前的滚动进度。 关键在于监听 scroll
事件,并根据滚动的百分比来更新 animation.currentTime
。由于我们要手动控制动画,所以duration设置成1即可。
总结与建议
特性 | 描述 | 优点 | 缺点 |
---|---|---|---|
KeyframeEffect |
定义动画的关键帧,描述动画在不同时间点的状态。 | 灵活地定义动画的各个阶段,支持各种CSS属性,方便创建复杂的动画效果。 | 语法相对繁琐,需要手动编写关键帧,对于简单的动画可能略显复杂。 |
AnimationTimeline |
管理动画的播放进度,提供全局动画时间。 | 提供了统一的时间轴,方便管理和同步多个动画,支持自定义时间轴,可以实现更高级的动画效果。 | 对于简单的动画来说,使用默认的时间轴就足够了,自定义时间轴的使用场景相对较少。 |
WAAPI | 一套JavaScript API,允许你通过代码创建、控制和操作Web动画。 | 提供了强大的动画控制能力,可以实现各种复杂的动画效果,性能优于传统的CSS动画,方便进行动画的编排和管理。 | 学习曲线相对较陡峭,需要理解WAAPI的各个概念和API,对于简单的动画可能略显复杂。 |
- 多实践: WAAPI 的概念和 API 比较多,需要多写代码才能真正掌握。
- 善用工具: 可以使用一些 WAAPI 的辅助工具,例如在线编辑器、动画库等,来提高开发效率。
- 关注性能: 复杂的动画可能会影响页面的性能,需要注意优化动画效果,避免过度使用 WAAPI。
- 逐步深入: 先从简单的动画开始,逐步尝试更复杂的动画效果,循序渐进地学习 WAAPI。
- 兼容性: 虽然 WAAPI 的兼容性已经比较好了,但在一些老版本的浏览器上可能需要使用 Polyfill。
总的来说,KeyframeEffect
和 AnimationTimeline
是 WAAPI 中非常重要的两个概念,它们为我们提供了更强大、更灵活的动画控制能力。 掌握了它们,你就可以用 JavaScript 写出各种炫酷的 Web 动画,让你的网站更加生动有趣。 好了,今天的讲座就到这里,希望对大家有所帮助! 咱们下期再见!