如何运行 一个requestAnimationFrame 动画持续一段时间?

How to run a requestAnimationFrame animation for a certain duration?

我有以下功能,通过每次“滴答”调整它们的样式,将一些元素“向上”滚动到视图之外:

const incr = 1;
let moved = 0;

function changeHeight( children, duration, setTop) {
  // duration = 1500
  const height = children.clientHeight; // in this case, 166px

  let moved = 0; 
  const slideUp = function (timestamp) {
    // we're done if the amount moved is larger than height
    if ( moved < height ) { 
      children.style.top = `${ setTop( moved, height ) }px`;
      moved = moved + incr // move by some amount

      requestAnimationFrame(slideUp) 

    } else {
      // reset
      moved = 0;
    }
  };

  // start sliding
  slideUp();
}

如果 requestAnimationFrame 大约每 16 毫秒左右触发一次,我想使用 duration 来指定动画 运行 的时长,因此公式似乎是 height * 16.5 / duration

我对 requestAnimationFrame 感到困惑 - 为什么每个滴答的时间不是恒定的?我想使用由 requestAnimationFrame 生成的 timestamp 但前几个周期比 ~16.5

的平均值长 很多

16.5 在不同的机器或屏幕上看起来会有所不同吗?

如何使高度变化恰好在指定的时间内完成?

你想要的叫做增量时间。 公式为Math.min((now - start) / duration, 1) * final_amount.

使用这个增量时间,你不需要关心你的间隔触发的频率,每一步都呈现在“它应该在的地方”。

关于你的问题,

why is the time per tick not constant

当然是因为浏览器在第一帧有很多事情要做,不能在 16.7 毫秒的帧内完成所有事情。因此,它会将您的回调移到稍后执行,如果压力太大,甚至可能会跳帧。

Is the 16.5 going to look different on a different machine or screen?

是的,requestAnimationFrame 基本上会尝试跟随显示器的刷新率。所以在 60Hz 的显示器上你确实每帧有 16.7ms,但在 120Hz 的显示器上你只有一半。

How do I make the height change take exactly the amount of time specified?

使用增量时间:

const elem = document.querySelector("div");
let moved = 0;
changeHeight(elem, 200, 5000);

function changeHeight(elem, height, duration) {
  const start = performance.now();
  const step = function () {
    const now = performance.now();
    const delta = Math.min((now - start) / duration, 1);
    elem.style.height = (delta * height) + "px";
    if (delta < 1) {
      requestAnimationFrame(step);
    }
  };
  step();
}
div { width: 50px; background: green; }
<div></div>