Window: requestAnimationFrame() 方法
基线 广泛可用
此功能已成熟,可在许多设备和浏览器版本中使用。它从 2015年7月.
报告反馈
window.requestAnimationFrame()
方法告诉浏览器您希望执行动画。它请求浏览器在下次重绘之前调用用户提供的回调函数。
回调函数的调用频率通常与显示刷新率匹配。最常见的刷新率是 60hz(每秒 60 个周期/帧),尽管 75hz、120hz 和 144hz 也被广泛使用。为了提高性能和延长电池寿命,在后台选项卡或隐藏的 <iframe>
中运行时,大多数浏览器都会暂停 requestAnimationFrame()
调用。
注意:如果您想为另一帧设置动画,您的回调函数必须再次调用 requestAnimationFrame()
。requestAnimationFrame()
是单次性的。
语法
requestAnimationFrame(callback)
js
参数
-
回调
时间戳
-
一个
DOMHighResTimeStamp
,表示上一帧渲染的结束时间(基于自 时间原点 经过的毫秒数)。时间戳是一个十进制数,以毫秒为单位,但最小精度为 1 毫秒。对于Window
对象(不是Workers
),它等于document.timeline.currentTime
。此时间戳在运行在同一个代理(所有相同来源的窗口,更重要的是,相同来源的 iframe)上的所有窗口之间共享——这使得可以跨多个requestAnimationFrame
回调同步动画。时间戳值也类似于在回调函数开始时调用performance.now()
,但它永远不会相同。当由
requestAnimationFrame()
排队的多个回调开始在一帧中触发时,即使在计算每个先前回调的工作量期间已经过去了时间,每个回调也会接收到相同的时间戳。
返回值
一个 long
整数,请求 ID,它唯一标识回调列表中的条目。这是一个非零值,但您不能对它的值做任何其他假设。您可以将此值传递给 window.cancelAnimationFrame()
以取消刷新回调请求。
示例
在本例中,元素动画持续 2 秒(2000 毫秒)。该元素以 0.1px/ms 的速度向右移动,因此它的相对位置(以 CSS 像素为单位)可以用动画开始以来的经过时间(以毫秒为单位)来计算,方法是 0.1 * elapsed
。元素的最终位置是其初始位置右侧 200px(0.1 * 2000
)。
const element = document.getElementById("some-element-you-want-to-animate");
let start;
function step(timeStamp) {
if (start === undefined) {
start = timeStamp;
}
const elapsed = timeStamp - start;
// Math.min() is used here to make sure the element stops at exactly 200px
const shift = Math.min(0.1 * elapsed, 200);
element.style.transform = `translateX(${shift}px)`;
if (shift < 200) {
previousTimeStamp = timeStamp;
requestAnimationFrame(step);
}
}
requestAnimationFrame(step);
以下三个示例说明了设置时间零点(用于计算每帧动画进度的基线)的不同方法。如果您想与外部时钟同步,例如 BaseAudioContext.currentTime
,则可用的最高精度是单个帧的持续时间,即 60hz 时为 16.67ms。回调的时间戳参数表示上一帧的结束,因此您新计算的值将在下一帧中最早被渲染。
此示例等到第一个回调执行后才设置 zero
。如果您的动画在开始时跳到一个新值,您必须以这种方式构建它。如果您不需要与任何外部内容(如音频)同步,那么建议使用这种方法,因为某些浏览器在第一次调用 requestAnimationFrame()
和第一次调用回调函数之间存在多帧延迟。
let zero;
requestAnimationFrame(firstFrame);
function firstFrame(timeStamp) {
zero = timeStamp;
animate(timeStamp);
}
function animate(timeStamp) {
const value = (timeStamp - zero) / duration;
if (value < 1) {
element.style.opacity = value;
requestAnimationFrame((t) => animate(t));
} else element.style.opacity = 1;
}
此示例使用 document.timeline.currentTime
在第一次调用 requestAnimationFrame
之前设置零值。document.timeline.currentTime
与 timeStamp
参数对齐,因此零值等效于第 0 帧的时间戳。
const zero = document.timeline.currentTime;
requestAnimationFrame(animate);
function animate(timeStamp) {
const value = (timeStamp - zero) / duration; // animation-timing-function: linear
if (value < 1) {
element.style.opacity = value;
requestAnimationFrame((t) => animate(t));
} else element.style.opacity = 1;
}
此示例使用 performance.now()
而不是回调的时间戳值来设置动画。您可以使用此方法来实现稍微更高的同步精度,尽管额外的精度是可变的,并没有很大程度的提高。注意:此示例不允许您可靠地同步动画回调。
const zero = performance.now();
requestAnimationFrame(animate);
function animate() {
const value = (performance.now() - zero) / duration;
if (value < 1) {
element.style.opacity = value;
requestAnimationFrame((t) => animate(t));
} else element.style.opacity = 1;
}
规范
规范 |
---|
HTML 标准 # dom-animationframeprovider-requestanimationframe |
浏览器兼容性
BCD 表格仅在启用 JavaScript 的浏览器中加载。