【问题标题】:jquery stop() all animations without letting deferreds $.when, .promise(), .done() return complete?jquery stop() 所有动画不让延迟 $.when, .promise(), .done() 返回完成?
【发布时间】:2012-11-05 16:43:10
【问题描述】:

似乎每 50-100 个 jsfiddle 更新都会引导我到 stackoverflow 社区来帮助解决我创建的新问题!非常感谢!

背景:我有几个包含动画的函数,函数要在前一个完成后触发。在一些帮助和研究下,我开始使用 $.when 和 .promise() 来控制这些东西,而不是我最初的非常丑陋的回调字符串和每个函数上的 setTimeouts。

我的困境是:在某些时候,用户可能想要暂停所有内容,然后在闲暇时重新开始。我似乎无法添加此功能!

我可以使用 $('div:animated').stop() 暂停所有动画,但这是暂时的,因为 .promise() 仍然可以解决!有什么办法可以覆盖这种行为?是否有任何重组可能有助于使暂停和恢复更容易实施?

明天我计划继续将所有动画添加到代理对象队列,但不确定在新对象上创建全局队列与现有结构的效果如何。我还打算考虑添加一些布尔值来检查值是否关闭,然后不要调用函数或进行动画处理。我不确定这些解决方案中的任何一个是否是我应该采取的适当方向?

在预览了这篇文章之后,我还想学习如何重构我的嵌套开始按钮功能!

我们将不胜感激任何有关实现暂停和恢复功能的指导。

下面的代码被大大简化了,每个函数都包含更多的元素和动画。

a fiddle here

JS:

    $('#start').click( function() {
    // run a and wait one second, when done run b and wait 1 second...
    a().delay(100).promise().done( function(){
        b().delay(100).promise().done( function(){
            c().delay(100).promise().done( function(){
                d().delay(100).promise().done( function(){
                    e().delay(100).promise().done( function(){
                        f().delay(100).promise().done( function(){
                            alert('all done!');
                        });
                    });
                });
            });
        });
    });


    });

    $('#reset').click( function() {
        $('.box').css({
            top: '0px'
        });
    });
    $('#pause').click( function() {
        $('div:animated').stop();
    });
   function a() {
        return $('.box1').animate({top: '100px'}, 1000, function(){
            $('.box1').animate({top: '50px'}, 1000);        
        });
        return $('.box6').animate({top: '200px'}, 4000);
    }
    function b(){
        return $('.box2').animate({top: '100px'}, 1000);
    }
    function c(){
        return $('.box3').animate({top: '100px'}, 1000, function(){
            $('.box3').animate({top: '50px'}, 1000);        
        });
    }
    function d(){
        return $('.box4').animate({top: '100px'}, 1000);
    }
    function e(){
        return $('.box5').animate({top: '100px'}, 1000, function(){
            $('.box5').animate({top: '50px'}, 1000);        
        });
    }
    function f(){
        return $('.box6').animate({top: '100px'}, 1000);
    }

​ html & CSS

<button id='start'>animate</button>
<button id='reset'>Reset</button>
<button id='pause'>pause</button>
<div class='boxes'>
    <div class='box box1'></div>
    <div class='box box2'></div>
    <div class='box box3'></div>
    <div class='box box4'></div>
    <div class='box box5'></div>
    <div class='box box6'></div>
</div>​
.boxes{position: relative}
.box{width: 40px; height: 40px; background-color: green; position:absolute;}
.box1{left: 0px;}
.box2{left: 60px;}
.box3{left: 120px;}
.box4{left: 180px;}
.box5{left: 240px;}
.box6{left: 300px;}
​

编辑 您的回答提供了我一直在寻找的学习经验;我真的很感激心灵的分享!我的人为示例可能无法充分展示现实世界的问题,因为所提出的答案不允许同时触发多个动画?我不认为至少?例如 box1 和 box2 可能同时移动,或者当 box3 触发时 box6 也会移动。我实现的最初的 VERY UGLY promise 系统使用了许多函数,因为每个函数都由许多动画组成。建议的答案将如何实现?

EDIT2 两个答案,charlietfl 让我可以轻松添加同时触发的辅助功能;很重要。 Alnitak 有一种优雅的方式来构造数组并将其应用于动画,非常容易更改动画类型(fadeOut()、fadeIn())。

所以我想要做的是将两者结合起来,这样我就可以为使用 Alnitaks 数组格式的辅助动画创建一个嵌套数组:

['.box1', 'animate', { top:  '50px'}, 1000],

简而言之,我仍在研究所有答案,但与 charlietfls 的答案接近/接近。将 Alnitak 的数组添加到他的数组或将 charlietfl 的嵌套添加到 Alnitak 的。

这比我想象的更加激烈;感谢您的贡献和代码,可以从中学习......非常有用!

【问题讨论】:

    标签: jquery animation promise deferred control-flow


    【解决方案1】:

    允许多个同时动画的 jQuery 方法非常好,但是当你的动画都是连续的时,它就有点过分了。

    我建议创建一组动画描述,然后在一个简单的循环中一次调用那些。

    每个描述都需要知道要为哪个元素设置动画、要调用哪个函数以及函数参数是什么。

    暂停动画只是一个不进行循环的问题:

    function next() {
        if (!animating) return;
    
        var a = list.shift();
        if (a) {
            var el = a[0];
            var fn = a[1];
            var args = a.slice(2);
            $.fn[fn].apply($(el), args).promise().done(next);
        } else {
            alert('all done!');
        }
    };
    

    请参阅http://jsfiddle.net/alnitak/ANRa3 以获取演示。

    【讨论】:

    • 这绝对可以工作,尤其是因为您可以跟踪动画脚本的进度并从中断的地方继续。
    • 我开始写一个 - 它不完整,因为我还没有添加“简历”功能。主要部分是演示如何使用 .apply 在元素上调用任意 jQuery 函数。 jsfiddle.net/alnitak/ANRa3
    • fml.这太干净了,伙计——如果我能再+1,我会的;只是关于$.fn.apply 和让生活变得有价值的自我执行功能。
    • 好的,我现在已经清理了一些。它现在可以愉快地恢复和重置。
    • 感谢您的贡献,非常感谢!你以前回答过我的一两个问题,太棒了!您能否评论我在问题底部所做的编辑?我对如何使用您的策略(比如 box3 和 box6)一次触发多个动画感到困惑,这是否意味着我必须创建一个数组数组来迭代?
    【解决方案2】:

    而不是使用animate的回调来调用二级动画,如果你链接animate().delay().animate()你可以返回二级动画的承诺。

    我的解决方案使用嵌套的对象数组,因此您可以轻松地在一个序列中添加任意数量的动画。诀窍是在组内创建一个包含所有承诺的数组,并使用该数组来确定整个动画组何时完成。

    样本数据:

    var animations = [
       /* first group array */
        [ {  "sel": ".box1","main": {"css": {"top": "100px"},"dur": 1000},
             "secondary": {"delay": 100,"css": {"top": "50px"},"dur": 1000    }
            },
            {"sel": ".box2","main": {"css": {"top": "100px"},"dur": 1000}},
           {"sel": ".box4","main": {"css": {"top": "100px"},"dur": 1000}},
          {    "sel": ".box5","main": {"css": {"top": "100px"},"dur": 1000},
                "secondary": {"delay": 100,"css": {"top": "50px"},"dur": 1000    }
            }      
        ],
         /* second group array */
        [ { "sel": ".box3","main": {"css": {"top": "100px"},"dur": 1000},
                "secondary": {"delay": 100,"css": {"top": "50px"},"dur": 1000    }
            },
           {"sel": ".box4","main": {"css": {"top": "100px"},"dur": 1000}}
        ]
    ];
    

    JS:

    var curr = -1;
    var paused = false;
    
    function animateBoxes() {
        if (paused) {
            return;
        }
        //curr = (curr + 1 < animations.length) ? curr + 1 : 0;
        curr=curr+1;
    
        if( !animations[curr]){
            alert('DONE!!');
            return;
        }
        /* array of animation deffereds*/
        var anims = [];
    
        $.each(animations[curr], function(i, currAnim) {
            var anim = boxAnimate(currAnim);
            anims.push(anim)
        });
    
        $.when.apply(null, anims).done(function() {
            animateBoxes();
        });
    }
    
    
    $('#start').click(function() {
        paused = false;
        animateBoxes();
    });
    
    $('#reset').click(function() {
        curr = -1;
        stopanimation();
        $('.box').css({
            top: '0px'
        });
    });
    $('#pause').click(function() {
        stopanimation();
    });
    
    
    function stopanimation() {
        paused = true;
        $('div:animated').stop(true, true);
    
    }
    
    function boxAnimate(obj) {
    
        var $el = $(obj.sel),
            anim;
        if (obj.secondary) {
            /* chain animate & delay to get promise for last effect */
            anim = $el.animate(obj.main.css, obj.main.dur)
                      .delay(obj.secondary.delay)
                      .animate(obj.secondary.css, obj.secondary.dur)
        } else {
            anim = $el.animate(obj.main.css, obj.main.dur)
        }
        return anim;
    }
    

    演示:http://jsfiddle.net/SWHTx/5/

    【讨论】:

    • 在这里感谢您的帮助!你介意评论我在帖子底部所做的编辑吗?我喜欢您的示例的简单性,不幸的是,现实世界的问题使用了许多动画类型,有些是同时触发的,有些是一个接一个。谢谢
    • 好吧..你勾起了我的好奇心。我用更强大的方法完全修改了我的答案,允许您在组中添加任意数量的动画。链接动画而不是使用回调更容易从最后一个效果中获得承诺
    • 哇!你的好!我需要将我的大脑包裹在链/次要承诺位(以及其他一些事情)上。我有fadeIn() 和fadeOut() 动画来集成,我要么尝试添加if / then,要么只是动画css 不透明度。你推荐什么方向?我真的很感激这一点。现实世界的动画非常庞大,我将在接下来的几天内开始使用您的策略来解决它,并在解决方案复选标记上回复您。谢谢
    • 请记住,fadeIn/fadeOut 也是动画,您也可以使用动画。有很多方法可以扩展对象和代码,比如向动画添加回调,这些回调对于开始下一组可能不是时间关键。您可以以标准化方式构建到对象中的越多,编码就越容易。如果不了解更多关于各种类型的效果以及可能链接在一起的效果,很难提供解决方案
    猜你喜欢
    • 1970-01-01
    • 2012-08-01
    • 2018-05-26
    • 2011-07-10
    • 1970-01-01
    • 2016-09-25
    • 2012-05-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多