简体   繁体   中英

Pausing Recursive Function Call

I have a function of which I'm supposed to pause on mouseenter and pause on mouseleave but the problem is that the function is recursive. You pass in a parent and index and it will recursively loop through each inner div displaying and hiding. The function looks like this:

var delay = 1000;
function cycle(variable, j){
    var jmax = jQuery(variable + " div").length;
    jQuery(variable + " div:eq(" + j + ")")
        .css('display', 'block')
        .animate({opacity: 1}, 600)
        .animate({opacity: 1}, delay)
        .animate({opacity: 0}, 800, function(){
            if(j+1 === jmax){ 
                j=0;
            }else{ 
                j++;
            }
            jQuery(this).css('display', 'none').animate({opacity: 0}, 10);

            cycle(variable, j);
        });
}

I've tried setting a timeout and clearing it but it doesn't seem to do anything (it seems to ignore the timeout entirely), I've tried using stop() and calling the function again on mouseout but that seemed to repeat the function call (I was seeing duplicates) and it stopped mid animation which didn't work. I tried adding in a default variable at one point ( var pause = false || true; ) but I also couldn't get it to work as expected (though I feel the solution relies on that variable). I'm open to all suggestions but there are some rules of engagement:

Rules: There can't be any major changes in how this function works as many things rely on it, it's something I do not have control over. Assume the function call looks like this jQuery('#divList', 0) and holds a bunch of div elements as children.

The timeout function is the last solution I tried which looks like:

jQuery('#divList').on('mouseenter', function(){
    setTimeout(cycle, 100000);
})
.on('mouseleave', function(){
    window.clearTimeout();
});

You will need to put a flag that each cycle checks before it determines if it is going to run. Then you can just change that flag when the mouse events are triggered. If you need to pick up where you left off when you unpause, consider saving the last value of j

function cycle(variable, j){
    if (window.paused) {
        window.last_j = j;
        return;
    }
    ...

Then when you want to pause, just set window.paused = true . To resume, change it back to false and call cycle again:

cycle(variable, last_j);

Perhaps something like this? I simplified the animation just to make the example simpler, but you should be able to adapt it to your needs.

First, we have a function that's responsible for animating a set of elements. Every function call returns a new function that allows to toggle the animation (transition between pause and resume).

function startCycleAnimation(els) {

    var index = 0,
        $els = $(els),
        $animatedEl;

    animate($nextEl());

    return pauseCycleAnimation;

    function animate($el, startOpacity) {
        $el.css('opacity', startOpacity || 1)
           .animate({ opacity: 0 }, 800, function () {
                animate($nextEl());
            });
    }

    function $nextEl() {
        index = index % $els.length;
        return $animatedEl = $els.slice(index++, index);
    }

    function pauseCycleAnimation() {
        $animatedEl.stop(true);

        return resumeCycleAnimation;
    }

    function resumeCycleAnimation() {
         animate($animatedEl, $animatedEl.css('opacity'));

         return pauseCycleAnimation;
    }
}

Then we can kick-start everything with something like:

$(function () {
    var $animationContainer = $('#animation-container'),
        toggleAnimation = startCycleAnimation($animationContainer.children('div'));

    $animationContainer.mouseenter(pauseOrResume).mouseleave(pauseOrResume);

    function pauseOrResume() {
        toggleAnimation = toggleAnimation();
    }
});

Example HTML

<body>
    <div id="animation-container">
        <div>Div 1</div>
        <div>Div 2</div>
        <div>Div 3</div>
    </div>
</body>

If you want something more generic, it seems there's a plugin that overrides animate and allows to pause/resume animations in a generic way.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM