【问题标题】:End a .each and a setTimeout()结束 .each 和 setTimeout()
【发布时间】:2015-07-22 17:58:28
【问题描述】:

我正在尝试使用 javascript 和 jQuery 找出停止/开始按钮。我设置了一个 jsfiddle 来尝试理解它,但我无法让它工作:http://jsfiddle.net/kkx7m88c/

开始按钮应一次将每个框变为红色。停止按钮应将所有框恢复为蓝色,并停止再变为红色,直到再次按下开始按钮。目前,停止按钮会将所有框变为蓝色但不会停止播放功能,这意味着尚未变为红色的框不会停止。它们变成红色。

这是我的 js:

// new class turns the boxes red with css

function goClasses(item, container) {
    $(container).removeClass('stopped');
    $(item).addClass('new');
}

function stopClasses(item, container) {
    $(item).removeClass('new');
    $(container).addClass('stopped');
}


$('#go').mousedown(function () {
    $('.box').each(function(i){
        var item = $(this);
        var container = $('.selection');
        setTimeout(function () {
            goClasses(item, container);
        }, 500 * i);
        if ($(container).hasClass('stopped')) {
            //clearTimeout(); /* this doesn't appear to do anything */
            //return false; /* this stops the 'go' button from working properly when clicked again after the 'stop' button has clicked */
        }
    });
});

$('#stop').mousedown(function () {
    $('.box').each(function (i) {
        var item = $(this);
        var container = $('.selection');
        stopClasses(item, container);
    });
});

我的理解是,如果我可以结束 mousedown 部分中的 setTimeout 和 .each ,它会起作用......但也许我完全关闭了它。也许我应该改用 setInterval() ?我是 jQuery 新手,所以我还在搞清楚!

【问题讨论】:

  • 我不认为你的问题出在计时器上,这是因为循环在进行。尝试从停止按钮设置一个标志并在启动函数中检查它以打破循环。

标签: javascript jquery html css


【解决方案1】:

存储对计时器的引用并取消它

$('#go').mousedown(function () {
    $('.box').each(function(i){
        var item = $(this);
        var container = $('.selection');
        var timer = setTimeout(function () {  //store the id that the setTimeout returns
            goClasses(item, container);
        }, 500 * i);
        item.data("timer", timer);  //store it as a data attribute
    });
});

$('#stop').mousedown(function () {
    $('.box').each(function (i) {
        var item = $(this);
        window.clearTimeout(item.data("timer"));  //check the data attribute for the timer and cancel it
        var container = $('.selection');
        stopClasses(item, container);
    });
});

【讨论】:

    【解决方案2】:

    你可以通过利用jQuery的.delay().promise()来完全避免setTimeout()

    这样做的好处是您可以使用 jQuery 的 .stop() 来消除延迟并停止整个进程。

    function goClasses($item, $container) {
        $container.removeClass('stopped');
        $item.addClass('new');
    }
    
    function stopClasses($item, $container) {
        $item.removeClass('new');
        $container.addClass('stopped');
    }
    
    $('#go').on('click', function () {
        var $selection = $(".selection");
        if(!$selection.data('running')) {
            $('.box').get().reduce(function(p, box) {
                return p.then(function() {
                    var $box = $(box);
                    goClasses($box, $selection);
                    return $box.delay(500).promise();
                });
            }, $.when());
            $selection.data('running', true);
        }
    });
    
    $('#stop').on('click', function () {
        stopClasses($('.box').stop(), $('.selection').data('running', false));
    });
    

    还包括一种机制,使“开始”按钮的行为更好,以防用户在动画序列正在进行时再次单击它。

    DEMO

    说明

    对这个答案采取的方法相当先进,所以如果你不能立即掌握它,请不要担心。

    如果您不熟悉 jQuery 的 Deferreds/Promises,那么您将需要对 Deferred Object 做一些背景阅读,并注意 .promise() 方法提供与动画完成相关联的承诺(包括延迟)。

    你还需要了解javascript的Array.prototype.reduce()方法。

    这个答案的核心是$('.box').get().reduce(...),它创建了一个包含.box 元素的数组,然后处理该数组以构建一个promise 链,并以$.when() 返回的已解析的jQuery 承诺为种子。

    随着链中的每个承诺都实现(表示动画步骤的完成),因此执行下一步,其可见方面是goClasses($box, $selection)。语句return $box.delay(500).promise() 在步骤之间施加了所需的 500 毫秒延迟。

    “停止”过程只是在所有 .box 元素上调用 .stop(),使任何待处理的 .delay(500) 无效,并确保相关的承诺永远不会实现。动画序列停止。

    $('.selection').data('running') 布尔值被管理为指示动画是否正在运行(和重置)。当true 时,此布尔值用于禁止启动另一个动画序列。

    我刚刚意识到$('.selection').data('running') 不是必需的。我可以改为测试$('.selection').hasClass('stopped')

    【讨论】:

    • 这有点超出我的想象......你能解释一下这里发生了什么吗?我似乎比使用 setTimeout() 更简洁,但我无法理解。
    • @Alana,我已经添加了解释,但正如我所说,如果您不明白,请不要担心。当你掌握了更多的 javascript 后,再来这里。
    猜你喜欢
    • 2018-02-17
    • 2010-11-19
    • 2021-06-08
    • 2019-04-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-06
    • 2012-02-06
    相关资源
    最近更新 更多