How to stop a javascript function from within anot

2019-07-07 04:27发布

问题:

I'm developing a simple slideshow system. I've got the slideshow wrapped in a hidden div, which is shown when a thumbnail from the gallery is clicked.

The slideshow works through a function called commence(), which is executed when the play button is clicked.

At the moment I've got it set to hide to whole div again when stop is clicked, but I would like to keep the div shown, simply stop the slideshow, in other words, stop the commence() function.

Can anyone tell me how to do this?

Here is my JS:

function commence() {
    hidden = document.getElementById("hidden");
    hidden.style.display = 'block';
    pause = document.getElementById("pause");
    pause.style.display = 'block';
    play = document.getElementById("play");
    play.style.display = 'none';
    pic = document.getElementById("picbox"); // Assign var pic to the html element.
    imgs = []; // Assign images as values and indexes to imgs array.

/* --------------------------- IMAGE URLS FOR IMGS ARRAY -------------------------*/

    imgs[0] = "/snakelane/assets/images/thumb/_1.jpg";  imgs[10] = "/snakelane/assets/images/thumb/_19.jpg"; 
    imgs[1] = "/snakelane/assets/images/thumb/_2.jpg";  imgs[11] = "/snakelane/assets/images/thumb/_20.jpg"; 
    imgs[2] = "/snakelane/assets/images/thumb/_3.jpg";  imgs[12] = "/snakelane/assets/images/thumb/_21.jpg";
    imgs[3] = "/snakelane/assets/images/thumb/_4.jpg";  imgs[13] = "/snakelane/assets/images/thumb/_22.jpg";
    imgs[4] = "/snakelane/assets/images/thumb/_5.jpg";  imgs[14] = "/snakelane/assets/images/thumb/_23.jpg";    
    imgs[5] = "/snakelane/assets/images/thumb/_6.jpg";  imgs[15] = "/snakelane/assets/images/thumb/_24.jpg";
    imgs[6] = "/snakelane/assets/images/thumb/_7.jpg";  imgs[16] = "/snakelane/assets/images/thumb/_25.jpg";
    imgs[7] = "/snakelane/assets/images/thumb/_8.jpg";  imgs[17] = "/snakelane/assets/images/thumb/_26.jpg"; 
    imgs[8] = "/snakelane/assets/images/thumb/_9.jpg";  imgs[18] = "/snakelane/assets/images/thumb/_27.jpg";
    imgs[9] = "/snakelane/assets/images/thumb/_10.jpg"; imgs[19] = "/snakelane/assets/images/thumb/_28.jpg"; 


/* -----------------------------------------------------------------------------------------------------*/


    var preload = []; // New array to hold the 'new' images.
    for(i = 0 ; i < imgs.length; i++) // Loop through imgs array
    {
        preload[i] = new Image(); // Loop preload array and declare current index as a new image object.
        preload[i].src = imgs[i]; // Fill preload array with the images being looped from ims array.
    }
    i = 0; // Reset counter to 0.
    rotate(); // Execute rotate function to create slideshow effect.
}

// Function to perform change between pictures.
function rotate() {
    pic.src = imgs[i]; // Change html element source to looping images
    (i === (imgs.length -1))?(i=0) : (i++); // counter equals imgs array length -1.
    setTimeout( rotate, 4000); // Sets the time between picture changes. (5000 milliseconds).
}


function init() {

    [].forEach.call(document.querySelectorAll('.pic'), function(el) { 
        el.addEventListener('click', changeSource); 
    });


    function changeSource() {  
        hidden = document.getElementById("hidden");
        hidden.style.display = 'block';
        newpic = this.src; 
        var pic = document.getElementById("picbox");
        pic.src = newpic;
    }
}

document.addEventListener("DOMContentLoaded", init, false);

function stopSlide() {
    var hidden = document.getElementById("hidden");
    hidden.style.visibility = 'hidden';
    pause.style.display = 'none';
    var play = document.getElementById("play");
    play.style.display = 'block';
}

The pause and play statements are not relevant to my question, they simply hide the play button and show the pause button if the slideshow is running, and vice versa.

回答1:

It looks to me like you actually want to stop the rotate() function, rather then commence, since rotate is what is actually changing the images (ie running the slideshow).

There are two ways. The first, like thriqon posted, is to use the clearTimeout function. However I'd recommend doing it like this:

// somewhere in global space
var rotateTimeout;

// in commence
rotateTimeout = window.setInterval(rotate,4000); // this will tell the browser to call rotate every 4 seconds, saving the ID of the interval into rotateTimeout

// in stopSlide
window.clearInterval(rotateTimeout); // this will tell the browser to clear, or stop running, the interval.

The second, which is a bit messier, is to use a sentinel.

// somewhere in global space
var running;

// in commence
running = true;
rotate();

// in stopSlide
running = false;

// in rotate
if (running) {
    setTimeout(rotate,4000);
}


回答2:

You want to use window.clearTimeout using the id you get by call window.setTimeout.

But you should also consider switching to window.setInterval, which gives you an function call every 4 seconds (and not 4 seconds after the last call), the not-needing of repeated calls to re-set the timeout and a better handling of missed events.

See this jsFiddle: http://jsfiddle.net/D3kMG/ for an example on how to use these functions for a simple counter.



回答3:

As mentioned by @thriqon you will want to use window.clearTimeout. To do this you need to save a "global" reference to the id returned by window.setTimeout, as follows:

var timeoutID;

//... function declarations

function rotate() {
    //...
    timeoutID = setTimeout( rotate, 4000);
}

Then in your stopSlide function you'll simply call clearTimout( timeoutID ) to stop the rotation.