如何在Web Animation API中反转无限动画?

问题描述

Web Animation API中,我们可以通过Element.animate界面对元素进行动画处理。返回的Animation对象可以通过.play().pause().reverse()播放,暂停或反转。

let img = document.querySelector('#happy-boy');

const boy_animation = [
    { transform: 'rotate(0)' },{ transform: 'rotate(360deg)' },];
const boy_timing = {
    duration: 3000,iterations: Infinity,}

let animation = img.animate(boy_animation,boy_timing);
animation.reverse(); // <-- fails with DOM exception

当我尝试反转动画时出现此错误

Cannot play reversed Animation with infinite target effect end.

chrome 86 on Linux

解决方法

reverse()的行为与play()一样,是如果动画在“结尾”,则它会跳回到起点并开始播放。

对于reverse(),这意味着如果在调用时当前时间为零(如您的示例中所示),则它应跳回到开头。但是,如果动画的长度是无限的,那意味着跳到无限!

如果只想向后运行动画的关键帧,则可以使用direction属性。

例如:

animation.effect.updateTiming({ direction: 'reverse' });

但是请注意,与reverse()不同的是,在动画进行过程中更新方向可能会导致其跳转位置。

如果要在 进行中 使其前后方向改变动画方向,并使其永久重复,则可以:

  1. 设置非常长的迭代计数,然后在该范围的中间开始动画,或者

  2. 使用updateTiming({ direction: 'reverse' })并调整currentTime,使其不会跳动。可能会发生以下情况:

     const ct = animation.effect.getComputedTiming();
     animation.currentTime =
         ct.currentInteration * ct.duration +
         (ct.duration - ct.localTime % ct.duration);
    

请注意,如果动画异步运行(例如,大多数变换和不透明度动画),则即使在(2)中使用updateTiming也会导致动画略微跳动,因为时间之间可能会有一些小的延迟在运行Javascript的主线程和正在运行动画的线程/进程上。

在(1)(或reverse())中使用updatePlaybackRate()可以避免该问题,因为它会在更新异步动画之前对其进行同步。