Установите время ожидания 5 секунд для одного номера в массиве, но не для всех сразу - PullRequest
0 голосов
/ 05 октября 2019

У меня есть массив с 100 числами, я хочу добавить активный класс к 20 из них, эта часть в порядке и работает. Но я хочу задержку между каждым числом.

Я пробовал с settimeout, но он задерживает все номера сразу на 5 секунд, но я хочу установить активный класс по одному с задержкой в ​​5 секунд. Пожалуйста, помогите.

function numbers() { 
                    
                        var activequantities;
                    activequantities = "@Html.DisplayFor(modelItem => item.Numbers)".split(",");
// this is array with sorted random numbers 20 of 100 example [22,33,46,57,etc]


                    function setClassNextItem(index)
{
    if (index >= activequantities.lenght) return;

    var value = activequantities[index];
    $(`.grid-container div[data-tabid=${value}]`).addClass('active');
    setTimeout(setClassNextItem(++index), 5000);
}

$(".grid-container div").removeClass('active');
                    setTimeout(setClassNextItem(0), 5000);

                        
                        
                }

<div class="grid-container">
        <div class="grid-item">

            <div class="grid-container2">
                <div class="grid-item2" data-tabid="1">1</div>
                <div class="grid-item2" data-tabid="2">2</div>
                <div class="grid-item2" data-tabid="3">3</div>
                <div class="grid-item2" data-tabid="4">4</div>
                </div>

Добавить активный класс по одному. С задержкой в ​​5 секунд между каждым номером.

Ответы [ 4 ]

1 голос
/ 05 октября 2019

Выполните итерацию по массиву отфильтрованных элементов и добавьте (index + 1) * interval тайм-аут для обратного вызова для добавления имени класса.

for (i = 0; i < 20; i++) {
  setTimeout(
    function (i) {
      //$this.addClass("active");
      console.log(`Add "active" class to element ${i}`);
    },
    (i + 1) * 1000, // shortened to 1 second for demo
    i
  );
}
0 голосов
/ 05 октября 2019

Ответ Дрю пока самый лучший и простой. Другой вариант - пойти по маршруту async function / promise.

/**
 * Time in milliseconds to wait between setting elements to active.
 */
const delayTime = 500, // shortened to half a second for the example
  $app = $('#app');

/**
 * Whether or not the routine is currently running.
 */
let stopped = true;

/**
 * Returns a promise that resolves after the specified number of milliseconds.
 */
function delay(ms) {
  return new Promise(res => setTimeout(res, ms));
}

function setActiveInSerial() {
  // a little user-friendly UI work
  stopped = !stopped;
  if (stopped) {
    $('#btn').text('Run');
  } else {
    $('#btn').text('Stop');
  }

  // promise that lets us serialize asynchronous functions
  let promise = Promise.resolve();

  $app.children().each(function() {
    promise = promise.then(async() => {
      if (stopped) {
        return;
      }

      $(this).addClass('active');

      // wait for `delayTime` to pass before resolving the promise
      await delay(delayTime);
      
      $(this).removeClass('active');
    })
  });
  
  // mark the routine as stopped and reset the button
  promise.then(() => {
    stopped = true;
    $('#btn').text('Run');
  });
}

// populate with items
for (let i = 1; i <= 20; i++) {
  $app.append($('<span>').text(`Item ${i}`));
}

// attach function to run button
$('#btn').click(setActiveInSerial);
#app {
  display: flex;
  flex-direction: column;
}

#app .active {
  background-color: cyan;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<button id="btn">Run</button>
<div id="app"></div>

Этот код, очевидно, длиннее, но он более гибкий и полезен для изучения обещаний и асинхронных функций. Дополнительным преимуществом является отсутствие необходимости поиска по всем дочерним элементам вашего элемента для удаления класса active.

0 голосов
/ 05 октября 2019

Добро пожаловать в stackoverflow! Функция setTimeout возвращает асинхронное обещание, которое разрешится в x мс. Если вы запускаете эту функцию в цикле, вы просто добавляете больше обещаний, которые нужно разрешить, но все они разрешатся близко к одному и тому же времени. Пример:

Отправить первое обещание: оно будет ждать 5 секунд
Через одну миллисекунду, отправить еще одно обещание, которое будет ждать 5 секунд
...
через 5 секунд, первое обещание разрешится правильно.
1 мс спустя, второе обещание разрешается правильно
...

Это поведение заставляет все ваши обещания разрешаться практически одновременно, всего через 5 секунд после их инициализации.

В вашем случае, поскольку вы хотите выполнять функцию с точным интервалом, вам нужен setInterval. Функция setInterval также требует времени в MS и функции, но она повторяет эту функцию каждые x мс или до тех пор, пока интервал не будет программно остановлен. Пример:

var counting = 0;
var myInterval = setInterval(function() {
    //we do something...
    console.log('loop:' + counting ++);
    if(counting === 10) {
        // we do this 10 times, than we stop the interval
        clearInterval(myInterval);
    }
}, 1000);

Здесь я использую интервал 1 с, потому что 5 слишком длинно для демонстрации.

0 голосов
/ 05 октября 2019

Попробуйте преобразовать activequantities в массив чисел и сделать что-то вроде этого:

function setClassNextItem(index)
{
    if (index >= activequantities.lenght) return;

    var value = activequantities[index];
    $(`.grid-container div[data-tabid=${value}]`).addClass('active');
    setTimeout(setClassNextItem(++index), 5000);
}

$(".grid-container div").removeClass('active');
setTimeout(setClassNextItem(0), 5000);

...