首页 > 解决方案 > javascript loop through dynamic array of elements, get values then use values as interval to set timer countdown

问题描述

I am making a timer that will use dynamically entered information to then display a count down timer for each entry. The timer will iterate over different values within a nodeList. These values will always be numeric values, Here is an example: 20, 7, 20, 7, 20, 7, 90, 20, 7, 20, 7, 20, 7, 90

These values represent blocks of seconds. So 20 seconds, then 7 seconds, then 20 seconds, then 7, etc...

I want to iterate over this list, get the values, then assign there values as seconds and loop through the list pausing for the defined time each time a new value is looped. I will be adding further nested code within this loop that counts down a timer set by each value accordingly, but I am not worried about the count down yet, just getting the iteration of each block of seconds to count down properly atm.

So using the example list above, I fire first value (20) immediately, pause 20 seconds(its value in seconds), then fire the next value (7), pause 7 seconds, then fire the next value pause for its value in seconds, so on until the entire list has expired.

NOTE: This info could always be different per form submission so the code must be dynamic in nature.

Here is the closest I have come in my attempt so far.

First, I have gathered the values using Javascript:

const span = document.querySelectorAll('.selector');

span--> represents input entries run through various foreach loops in php coming from different entries, all with the class value of .selector inserted in each corresponding input tag. The forming of iteration over the list will always be indexed properly in time for looping through the values as I have described.

This gives me the node list.

I gather the values in a foreach loop using .textContent, then I set an interval as a variable, get the value of the next sibling, run conditionals to set the interval, then check the firing of the loop for consistency. See my snippit below

span.forEach(function(value){
    const data = value.textContent;

    // Now that I have the nodelist values I run them through `setInterval`
    let delay = setInterval(engine => {
        const { value, set } = engine.next()
        if (set) {
            clearInterval(delay)
        } else {
            const values = value.textContent;
            console.log('firing delay -> ' + values);
        }  
    }, data * 1000, span[Symbol.iterator]())
})

The delay fires, but it is inconsistent and is not in time with proper seconds count down. I am not opposed to using a different method to get this achieved as I am a novice at JS and still learning how it works really. Any assistance would be greatly appreciated!

Again, I want to iterate over the nodelist, get its values, use those values as blocks of seconds, loop through the list pausing for each value as seconds, then moving to the next value until the list is completed.

UPDATE May 4th, 2020: Using Cedrics updated reduce code I am able to get the dynamic timeout working to display each iteration through the node list using its set value as seconds, then count down those seconds individually.

const spans = [...document.querySelectorAll('.selector')];
const timerEl = document.getElementById('timer');
const count = spans.length;
function countDown(secs,elem){
    const timerEl = document.getElementById(elem);    
    timerEl.innerHTML = `${secs}`;    
    if(secs === 1){
        clearTimeout(timer);
        return timer;
    }    
    secs--;
    var timer = setTimeout('countDown('+secs+',"'+elem+'")',1000);
}

let i = 0;
spans.reduce((totalDelay, span) => {    
    setTimeout(() => {   
        const circuits = document.querySelectorAll('.selector');
        const circuit = circuits[i].innerText;         
        let alt = circuits[i].attributes[0].textContent;
        let time = delay;
        console.log(alt)                    
        console.log(`${circuit} -> ${delay}`);
        console.log(`${i + 1} of ${count}`);
        //need logic to figure out if node is last item in list then display finished
        countDown(delay,"timer");            
        i++;         
    }, 1000 * totalDelay);
    const delay = parseInt(span.textContent);
    totalDelay += delay;    
    return totalDelay;
}, 0);
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Cool Down" class="selector">10</span>
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Workout" class="selector">5</span>
<span alt="Break" class="selector">3</span>
<span alt="Cool Down" class="selector">10</span>
<div id="timer"></div>

标签: javascriptloopsforeachnodesintervals

解决方案


如果我理解正确并且如果我重新使用您的示例,您想在 20 秒后执行一些代码,然后在 7 秒后,然后 20 秒......等等。

我建议setTimeout为每个跨度使用一个。它们都在同一时间开始。第一个使用 20 秒的延迟,第二个使用 27 秒的延迟(前一个 20 秒setTimeout+ 7 秒),第三个使用 47 秒的延迟(前一个setTimeout+ 20 秒的 27 秒)......你'我明白了。

我用来reduce记录之前的延迟。

const spans = [...document.querySelectorAll('.selector')];

spans.reduce((totalDelay, span) => {
    
    setTimeout(() => {
        console.log(`firing delay -> ${delay}`);
    }, 1000 * totalDelay);
    
    const delay = parseInt(span.textContent);
    totalDelay += delay;
  
    return totalDelay;
}, 0);
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">90</span>
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">20</span>
<span class="selector">7</span>
<span class="selector">90</span>


推荐阅读