Creé una presentación de diapositivas automática, que comienza después de hacer clic en "elemento de menú". Estoy buscando una manera de "apagarlo", al hacer clic en diferentes "elementos de menú". Todo el problema se puede resumir en un ejemplo simple:
Construyendo funcionalidad para "stop" <li> (que probablemente utilizaría stopInterval ). No puedo encontrar una solución, ¿alguien tiene una idea?
const li1 = document.getElementById("li1") li1.addEventListener("click", slideShowAbstract) function slideShowAbstract(e) { const y = setInterval(()=> console.log("playing"), 2000) } ul { display: flex; justify-content: center; list-style-type: none; } li { margin: 1rem; } li:hover { cursor: pointer; } <ul> <li id="li1">play</li> <li id="li2">stop</li> </ul>Puede declarar la y externa para poder acceder a ella desde varios controladores.
const li1 = document.getElementById("li1") const stopElement = document.getElementById("stopButton") let intervalTimer; li1.addEventListener("click", slideShowAbstract); stopElement.addEventListener('click', stopSlideShow); function slideShowAbstract(e) { intervalTimer = setInterval(() => console.log("playing"), 2000); } function stopSlideShow(){ clearInterval(intervalTimer); }una mejor manera ?
para evitar tener variables globales que puedan verse afectadas por efectos secundarios, use un objeto al que pueda agregar sus métodos útiles.
const btPlay = document.querySelector('#bt-play') , player = (()=> // IIFE for object { play(), stop() } method { let refIntv = 0, counter = 0 // inside Object values ( closure ) ; function playerAction() // inside private function { console.clear() console.log( 'playing', ++counter) } return { play() { counter = 0 console.clear() console.log('start playing') refIntv = setInterval( playerAction , 2000) } , stop() { clearInterval( refIntv ) console.clear() console.log('stop playing') } } })(); btPlay.onclick =_=> { if (btPlay.classList.toggle('stopped')) player.play() else player.stop() } #bt-play { margin : 1em 3em; width : 5em; } #bt-play::after { content : 'play'; } #bt-play.stopped::after { content : 'stop'; } <button id="bt-play"></button> <!-- control by interface : same button for start and stop --> interfaz de control :
si tiene 2 botones (inicio + parada), el usuario puede hacer clic 2 veces en el botón de inicio y termina con 2 procesos de intervalo superpuestos (o más) sin la posibilidad de encontrar la referencia del setInterval anterior ya que esta variable tiene ha sido reemplazado para hacer referencia al proceso del siguiente intervalo
si no, también puede agregar una prueba que verifique que no haya un proceso de intervalo en ejecución antes.
Detalles comentados en el ejemplo
// Reference both items const li1 = document.getElementById("li1"); const li2 = document.getElementById("li2"); // Bind both items to click event but call different handlers li1.addEventListener("click", start); li2.addEventListener("click", stop); // Declare interval ID let y; // Define time interval let t = 2000; // Define counter let tick = 0; // Define the function to run on each interval const log = () => console.log(t * tick++); // Define the event handler called from li1 function start(e) { // If the tag clicked was #li1 and y isn't defined yet... if (e.target.matches('#li1') && !y) { // ...Initiate interval to call log() y = setInterval(log, t); } } // Define the event handler called from li2 function stop(e) { // If user clicked #li2... if (e.target.matches('#li2')) { // ...Stop interval... clearInterval(y); // ...reset interval ID y = null; } } ul { display: flex; justify-content: center; list-style-type: none; } li { margin: 1rem; } li:hover { cursor: pointer; } <ul> <li id="li1">play</li> <li id="li2">stop</li> </ul>