首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >JavaScript:在requestAnimationFrame循环中使用cancelAnimationFrame

JavaScript:在requestAnimationFrame循环中使用cancelAnimationFrame
EN

Stack Overflow用户
提问于 2014-08-19 05:10:58
回答 1查看 2.1K关注 0票数 0

为了学习,我正在为所有的HTMLElements创建一个动画函数,它是受jQuery启发的。动画启动得很好,但是我希望它在请求动画框架的time =函数中给出的duration之后停止。我在动画循环中使用cancelAnimationFrame,但它不会停止循环。

代码语言:javascript
复制
    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)
        }
    }

函数的调用如下所示

代码语言:javascript
复制
    c.animate({"property":"value"},1)
EN

回答 1

Stack Overflow用户

发布于 2014-08-19 09:03:11

问题的核心在于这样一个事实:您只获得第一个动画帧( var aniLoop = (...)行)的ID,而这正是您要取消的内容--除了每个对requestAnimationFrame的调用都有不同的ID,因此您需要存储最后一个调用的返回值,然后取消它:

代码语言:javascript
复制
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函数声明

为了更好地了解函数声明和表达式的区别,我建议您阅读一下有关函数的内容,但是这里的问题是,您在循环中进行函数声明,这被认为是未定义的行为(一些引擎将替换函数,一些引擎将取代函数,有些引擎会崩溃)。假设动画只有一个给定的持续时间,因此可能是同步的,那么迭代属性以在单个动画函数中动画是一个更好的选择,如下所示:

代码语言:javascript
复制
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动画时间戳

目前看来,您的动画函数可能不会运行超过一个帧--如果您查看关于MDN的requestAnimationFrame文档,您会注意到给requestAnimationFrame的回调是一个时间戳,即从UNIX时代开始(1970年1月1日)开始的毫秒值--因此time >= (duration * 1000)的条件总是正确的。相反,请在启动动画时注册启动时间,并将回调中的时间戳与其进行比较,如下所示:

代码语言:javascript
复制
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的目的是由浏览器自动调节和调节,因此您不需要对动画是否应该运行应用自己的条件(无论如何,它不会超过60 you,因为这是规范的上限)。相反,它应该从一开始就简单地处理当前时间的差异,以确保您的动画仍然在正确的位置结束,即使由于某种原因,动画中有一个延迟:

代码语言:javascript
复制
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);
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25376013

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档