Web-Animation-API释放JavaScript中CSS关键帧的强大功能

8次阅读

共计 9936 个字符,预计需要花费 25 分钟才能阅读完成。

如果您曾经使用过 CSS3 关键帧动画,那么您可能会对这个功能感到非常欣赏并感到受到严重阻碍。一方面,CSS 关键帧允许您使用纯 CSS 创建复杂的动画,尽管其中也存在问题 – 所有内容都必须在 CSS 内部预先声明。我最喜欢的 jQuery 方法之一就是这个 animate()方法,它可以让我快速设置元素动画,而无需在 CSS 和 JavaScript 之间来回切换。

从 jQuery 获取页面,JavaScript 的 Web Animation API 最终提供了一种简单的本机 JavaScript 方法,可以使用 CSS 关键帧的全部功能为元素设置动画,而无需离开 JavaScript 环境。方便的方法和事件处理程序允许您暂停,倒回,跳转到动画时间轴中的某个点,等等。

好的,首先是所有重要的问题 – 浏览器兼容性。根据 CanIuse 的说法,除了 IE 之外,所有主流浏览器都支持 Web Animation API 的核心功能:

To start using WAAPI today, you can turn to the web-animation API polyfill, which brings IE as well onto the playing field. So no more excuses to not continue reading!

要立即开始使用 WAAPI,您可以转向 web 动画 API polyfill,它将 IE 也带到了游戏领域。所以没有更多的借口不继续阅读!

创建一个简单的关键帧 Web Animation
要使用 Web Animation API 为关键帧动画设置动画,只需 animate()在元素上调用该函数:

1
<font style=”vertical-align: inherit;”><font style=”vertical-align: inherit;”>Element.animate(关键帧,关键帧选项)</font></font>
This function accepts two arguments:

keyframes: Array of literals containing a JavaScript representation of the desired CSS keyframes

keyframeOptions: A literal containing additional settings for the animation, such as easing, duration, fill-mode etc.

Take a look at the following simple example, which uses the animate() function instead of CSS keyframes to render an animation:

该函数接受两个参数:

keyframes:包含所需 CSS 关键帧的 JavaScript 表示的文字数组

keyframeOptions:包含动画的其他设置的文字,例如缓动,持续时间,填充模式等。

看一下下面的简单示例,该示例使用 animate()函数而不是 CSS 关键帧来渲染动画:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<font style=”vertical-align: inherit;”><font style=”vertical-align: inherit;”>var boxframes = [</font></font><font></font><font style=”vertical-align: inherit;”><font style=”vertical-align: inherit;”>

{</font></font><font></font><font style="vertical-align: inherit;"><font style="vertical-align: inherit;">
    变换:'translateX(0)',</font></font><font></font>
    background: 'red',<font></font>
    borderRadius: 0<font></font>
},<font></font>
{<font></font>
    transform: 'translateX(200px) scale(.5)', <font></font>
    background: 'orange',<font></font>
    borderRadius: 0,<font></font>
    offset: 0.6 /* set explicit point (60%) when frame starts */<font></font>
},<font></font>
{<font></font>
    transform: 'translateX(400px)',<font></font>
    background: 'green',<font></font>
    borderRadius: '50%'<font></font>
}<font></font>

]
如果我们使用纯 CSS 声明上面的内容,它看起来像这样:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@keyframes animatethebox{<font></font>

0%{<font></font>
    transform: translateX(0);<font></font>
    background: red;<font></font>
    borderRadius: 0;<font></font>
}<font></font>
<font></font>
60%{<font></font>
    transform: translateX(200px) scale(.5);<font></font>
    background: orange;<font></font>
    borderRadius: 0;<font></font>
}<font></font>
<font></font>
100%{<font></font>
    transform: translateX(400px);<font></font>
    background: green;<font></font>
    borderRadius: 50%;<font></font>
}<font></font>

}
正如您所看到的,这两种语法非常相似,如果您已经熟悉 CSS 关键帧,那么将它移植到 JavaScript 就没有问题。与 JavaScript 版本的一些区别值得记住:

在 JavaScript 版本中,属性字符串值应该在引号(transform: ‘translateX(0)’)中

带连字符的属性名称必须转换为 camelCase 而不是(borderRadius: 0)。

逗号而不是分号应该跟踪每个属性声明(最后一个属性除外)

默认情况下,使用 JavaScript 设置的关键帧在播放时均匀分布,每个关键帧的时间相同。但是,通过 offset 在关键帧中添加属性,我们可以设置该关键帧应该开始播放的点,例如 60%标记的 0.6,类似于使用纯 CSS 的关键帧。

keyframeOptions 参数
该 animate()方法的第二个参数是一个文字,可以很好地调整动画的行为。许多选项直接从 CSS 的 animation-* 属性映射,例如“animation-delay”,“animation-fill-mode”等。所有属性都是可选的,如果没有设置,则回退到默认值:

property CSS Property Equivalent Description
id none Option that sets the name of this Animation to refer back to later in your code.
delay animation-delay The delay (integer) before the animation starts in milliseconds. Defaults to 0s.
direction animation-direction Defines whether the animation should play as normal, in reverse, or alternate between the two. Possible values are:
normal: The animation plays forward as normal. After each animation cycle, the animation resets to the beginning state and starts over again. Default value.
reverse: Plays the animation in reverse, starting from the end state. After each animation cycle, the animation resets to the end state and starts over again.
alternate: The animation alternates between normal and reverse directions. In reverse, the animation starts at the end state and plays backwards. The animation timing function is also reversed.
alternate-reverse: The animation alternates between reverse and normal directions, starting in reverse for the first iteration.
duration animation-delay The duration (integer) of the animation in milliseconds, such as 1000. Default to 0 (no animation, jumps to last frame).
easing animation-timing-function Sets the easing function used to animate the @keyframe animation. Valid values include “ease”, “ease-in”, “ease-in-out”,”linear”, “frames(integer)” etc. Defaults to “linear”.
endDelay n/a The number of milliseconds to delay after the end of an animation. This is useful when sequencing multiple animations based on the end time of another animation. Defaults to 0.
fill animation-fill-mode Defines how the animation should apply styles to its target when the animation isn’t playing anymore. Defaults to “none”. Possible values are:
none: The animation should not apply any styles to the target when it is not playing. Default value.
forwards: The target element will retain the computed styles defined in the last key frame (ie: when key frame is at 100%) when the animation isn’t playing.
backwards: The target element will retain the computed styles defined in the first key frame (ie: when key frame is at 0%) when the animation isn’t playing.
both: The target element will retain the computed styles defined in both the first and last key frames when the animation isn’t playing.
iterationStart n/a Sets the point in the iteration the animation should start. The value should be a positive, floating point number. In an animation with 1 iteration, a iterationStart value of 0.5 starts the animation half way through. In an animation with 2 iterations, a iiterationStart value of 1.5 starts the animation half way through the 2nd iteration etc. Defaults to 0.0.
iterations

animation-iteration-count Sets the number of times the animation should run before stopping. A value of Infinity means forever. Defaults to 1.
这是我在上面的例子中使用的 keyframeOptions 参数:

1
2
3
4
5
6
var boxref = document.getElementById(“box”)<font></font>
boxref.animate(boxframes, {<font></font>

duration: 1000,<font></font>
fill: 'forwards',<font></font>
easing: 'ease-in'<font></font>

})
如果我们想使用动画速记属性在 CSS 中定义相同的选项,它将如下所示:

1
animation: animatethebox 1s ease-in forwards;
控制动画(播放,暂停等)
使用 Animation API 创建关键帧动画的部分优点是可以按需操作结果,例如暂停,跳过或挂钩到动画的事件处理程序。执行所有这些操作的第一步是在调用 animate()方法时将动画分配给变量:

var myanimation = Element.animate(keyframes, keyframeOptions)

这将创建对 Animation 对象实例的引用,以允许我们通过各种公开的属性和方法来操作动画:

1
2
3
4
var myanimation = Element.animate(/ .. /)<font></font>
myanimation.pause() // immediately pause animation to control it manually<font></font>
myanimation.curentTime = 1000 // jump to 1 second from start of animation<font></font>
myanimation.play() // play animation

这是修改后使用控件进行回放的原始示例:

请注意,在此示例中,我 animate()立即调用目标元素,这将导致动画立即运行。为了防止这种情况,我 pause()随后调用了该 方法。这是您希望手动控制动画时使用的常用模式:

1
2
3
4
5
6
7
var boxanimation = boxref.animate(boxframes, {<font></font>

duration: 1000,<font></font>
fill: 'both',<font></font>
easing: 'ease-in'<font></font>

})<font></font>
<font></font>
boxanimation.pause()
动画对象实例属性和方法
下面列出了动画对象实例的属性,方法和事件处理程序,如上所述,在为 animate()方法分配引用时创建:

属性

currentTime: Gets or sets the current time value of the animation in milliseconds.
effect: Gets or sets the target effect of an animation. Support for this property is currently limited in all browsers.
finished: A promise object that’s resolved when the animation has completed. Support for this property is currently limited in all browsers.
id: Gets or sets a string used to identify the animation.
playbackRate: Integer that gets or sets a playback rate of the animation. For example, 1=normal, 0 = pause, 2 = double, -1 = backwards etc.
playState: Read-only property that returns the current state of the animation: “idle”, “pending”, “running”, “paused”, or “finished”.
ready: A promise object that’s resolved when the animation is ready to be played. Support for this property is currently limited in all browsers.
startTime: Floating point number that gets or sets the current time (in milliseconds) of the animation.
timeline: Gets or sets the current timeline of the animation. Defaults to the document timeline (document.timeline). Support for this property is currently limited in all browsers.
方法

cancel(): Cancels the animation.
finish(): Immediately completes an animation.
pause(): Pauses an animation.
play(): Plays an animation.
reverse(): Reverses the current direction of the animation and plays it.
事件处理程序

oncancel: Triggered when the animation is canceled, such as by calling the cancel() method.
onfinish: Triggered when the animation is finished, such as by calling the finish() method.
使用 Web Animation API 创建简单的 scrubber
通过操作 currentTime 属性,下面为我们看到的基本动画添加了一个简单的擦除器:

我创建了一个 HTML5 Range Slider 来用作 scrubber。当动画首次运行(自动)时,动画的 currentTime 属性值将持续传送到滑块,以使两者同步。目前没有“onprogress”事件处理程序或类似的东西(据我所知)只在 WAAPI 动画运行时运行代码,所以我用它 来监视动画的进度。动画结束后,我利用 WAAPI 事件调用并不必要地停止更新滑块。requestAnimationFrame()onfinishcancelAnimationFrame()

每当用户与 Ranger Slider 交互时,我都会更新 WAAPI 动画以与滑块同步:

1
2
3
4
5
6
7
8
9
10
11
12
scrubber.addEventListener(‘mousedown’, ()=>{<font></font>

boxanimation.pause()<font></font>
updateScrubber()<font></font>

})<font></font>
<font></font>
scrubber.addEventListener(‘mouseup’, ()=>{<font></font>

boxanimation.play()<font></font>

})<font></font>
<font></font>
scrubber.addEventListener(‘input’, ()=>{<font></font>

boxanimation.currentTime = scrubber.value * animationlength<font></font>

})
当用户按下滑块时,我暂停动画并更新滑块的值以与动画的 currentTime 属性同步。当用户拖动滑块时,反过来发生 – 我同步 currentTime 属性以反映滑块的值,因此前者依赖于后者。最后,当用户将鼠标放在滑块上时,我恢复动画的自动播放。

一次动画多个元素
在下一个示例中,我将使用 WAAPI 一次演示动画多个元素,并在它们全部结束后执行动作。

注意:在撰写本文时,即使在 Chrome 和 FF 中,对 WAAPI 承诺的原生支持也很不稳定。我不得不使用 Web Animation Next Polyfill 来使这个功能在浏览器中运行。

这里没有什么太复杂的事了。基本上我循环并调用 animate() 标题中的每个字母,并将每个 Animation 对象实例存储在数组中。有了这个数组,我可以根据需要循环播放一系列动画。每个动画的 finished 属性都返回一个 Promise,该动画在动画完成播放时被解析,我利用 Promise.all()在所有动画完成播放时重置整个动画。

使用 Animation()构造函数创建动画
到目前为止,我只使用 animate()对象直接在一个元素上创建了 WAAPI 动画,该元素返回一个 Animation 对象实例。我会失职但更不用说你也可以使用 Animation() 构造函数来完成同样的事情。

注意:Animation()在撰写本文时,即使在 Chrome 和 FF 中,本机支持也是不稳定的。我不得不使用 Web Animation Next Polyfill 来使这个功能在浏览器中运行。

有了警告,这里是如何调用 Animation() 构造函数:

1
var myanimation = new Animation(effect);
该函数接受两个参数:

effect:动画效果。在撰写本文时,仅 keyframeEffect 支持该对象。
timeline:动画时间轴。在撰写本文时,仅 document.timeline 支持。
让我们看一下如何使用一个简单的例子:

这是 JavaScript 代码:​

1
2
3
4
5
6
7
8
9
10
11
12
13
14
var boxref = document.getElementById(“box”)<font></font>
<font></font>
var boxkeyFrames = new KeyframeEffect(<font></font>

boxref, // element to animate<font></font>
[<font></font>
    {transform: 'translateX(0) rotate(0deg)', background:'red' }, // keyframe <font></font>
    {transform: 'translateX(90vw) rotate(180deg)', background:'blue' }<font></font>
], <font></font>
    {duration: 2000, fill: 'forwards', iterations: 5} // keyframe options<font></font>

);<font></font>
<font></font>
var boxanimation = new Animation(boxkeyFrames, document.timeline)<font></font>
<font></font>
boxanimation.play()
新 KeyframeEffect()对象是一个一体化对象,它包含一个位置的动画的所有设置,从目标元素,要使用的关键帧到关键帧选项。

正文完
 0