为了学习,我为所有HTMLElements设计了一个动画函数原型,该模型受jQuery启发。动画启动正常,但是我希望在函数中给定requestAnimationFrame的time
= duration
之后停止动画。我在动画循环内使用了cancelAnimationFrame
,但它并没有停止循环。
HTMLElement.prototype.animate = function(properties,duration){
for(prop in properties){
var last = 0,
fps = 60;
function ani(time){
requestAnimationFrame(ani);
if ((time - last) > fps ){
last = time
console.log(time)
if(time >= (duration*1000)){
window.cancelAnimationFrame(aniLoop)
}
}
}
var aniLoop = requestAnimationFrame(ani)
}
}
该函数这样调用
c.animate({"property":"value"},1)
最佳答案
问题的核心在于,您仅获得第一个动画帧的ID(var aniLoop = (...)
行),而这就是您要取消的事实-除了每次对requestAnimationFrame
的调用都不同之外ID,因此您需要存储上一次调用的返回值,然后取消该调用:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
prop,
last = 0,
fps = 60;
for (prop in properties) {
function ani(time) {
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
console.log(time);
if (time >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
aniLoop = requestAnimationFrame(ani);
}
};
但是,您的代码还有其他一些问题也需要解决,否则您的函数将被彻底炸毁:
:1循环中的函数声明
我建议阅读有关differences between function declaration and expression的信息,以获得更好的画面,但是这里的问题是您正在循环中进行函数声明,这被认为是未定义的行为(某些引擎将替换函数,某些引擎将替换该函数,某些引擎将打击该函数)向上)。鉴于动画只给出了一个持续时间,因此可能是同步的,所以最好在属性上进行迭代以在单个动画函数中进行动画处理,如下所示:
HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
last = 0,
fps = 60;
function ani(time) {
var prop;
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
for (prop in properties) {
console.log(prop + ': ' + time);
}
if (time >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
aniLoop = requestAnimationFrame(ani);
}
:2动画时间戳记
从目前的情况看,您的动画功能可能至少不会运行一帧-如果您查看requestAnimationFrame documentation on MDN,您会注意到,给
requestAnimationFrame
的回调具有时间戳记,即从开始起以毫秒为单位的值UNIX时代(1970年1月1日)的日期-因此time >= (duration * 1000)
的条件将始终为true。取而代之的是,在动画开始时注册开始时间,然后将回调中的时间戳与其进行比较,如下所示:HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
start,
last = 0,
fps = 60;
function ani(time) {
var prop,
progress;
aniLoop = requestAnimationFrame(ani);
if ((time - last) > fps) {
last = time;
progress = time - start;
for (prop in properties) {
console.log(prop + ': ' + progress + ' out of ' + (duration * 1000));
}
// This is where we get a difference between current and starting time
if (progress >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
}
start = Date.now();
aniLoop = requestAnimationFrame(ani);
}
:3动画节流
这不是很关键,但仍然值得考虑-
requestAnimationFrame
旨在由浏览器自动调节和调节,因此您不需要对是否应运行动画应用自己的条件(不会运行)超过60FPS,因为这是规范的上限)。相反,它应该仅处理当前时间与开始时间之间的时差,以确保即使由于某些原因动画存在滞后,动画仍可以正确地结束:HTMLElement.prototype.animate = function(properties,duration) {
"use strict";
var aniLoop,
start;
function ani(time) {
var prop,
progress;
aniLoop = requestAnimationFrame(ani);
progress = time - start;
for (prop in properties) {
console.log(prop + ': ' + progress + ' out of ' + (duration * 1000));
}
// This is where we get a difference between current and starting time
if (progress >= (duration * 1000)) {
cancelAnimationFrame(aniLoop);
}
}
start = Date.now();
aniLoop = requestAnimationFrame(ani);
}
关于javascript - JavaScript:在requestAnimationFrame循环中使用cancelAnimationFrame,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/25376013/