Задать вопрос
Alexanevsky
@Alexanevsky
Любительская web-разработка

Как постепенно выполнять действия, а потом всё повторять?

Здравствуйте!

Проблема, как мне кажется, очень простая.

Есть следующая структура:
<div class="block-1"></div>
<div class="block-2"></div>
<div class="block-3"></div>

Необходимо сделать всё по примерно такому алгоритму:
  1. Добавить для block-1 класс active;
  2. Через 500 мс. - добавить для block-2 класс active;
  3. Через 400 мс. - добавить для block-3 класс active;
  4. Через 300 мс. - снять со всех блоков классы active и запустить всё заново.

Есть ряд проблем, с которыми я столкнулся при попытке сделать что-то подобное.

На каждое действие отводится какое-то количество мс., так как это своего рода анимация, т.е., например:
.block-1 имеет стили height: 0; transition: height .5s linear;
а .block-1.active имеет height: 100px;
Получается, что за 0.5s высота блока должна стать 100px.

Я пытался добавить delay, т.е.
$('.block-1').addClass('active');
$('.block-2').delay(500).addClass('active');
$('.block-3').delay(900).addClass('active');
...

Но delay почему-то не хочет работать с addClass. Тогда я использовал не addClass, a animate, т.е.
$('.block-1').animate({height: 100px}, 500);
$('.block-2').delay(500).animate({height: 100px}, 400);
$('.block-3').delay(900).animate({height: 100px}, 300);
...

Тем самым, я вообще убрал класс active и всё делал сразу через JS. Всё работает, но есть одна проблема. Мне необходимо именно addClass, а не animate. Это вызвано необходимостью адаптировать всё это дело под разные размеры экрана, т.е. примерно по такой схеме:
.block-1.active {height: 100px;}
@media (max-width: 1000px) {
      .block-1.active {height: 50px;}
}
@media (max-width: 700px) {
      .block-1.active {height: 10px;}
}

И т.п.
Адаптировать просто в CSS, не трогая JS, гораздо проще, чем вносить изменения в сам скрипт.

Вторая проблема - это delay. Delay ведёт свой отчёт от самого начала, а не от предыдущего delay. Т.е. чтобы каждое действие происходило через несколько мс после предыдущего, мне надо делать так:
  1. Первое действие;
  2. Второе действие - delay: 500 ms;
  3. Третье действие - delay: 900 ms;
  4. Четвёртое действие - delay: 1200 ms.

В таком виде проблемы нет, но это просто пример кода и на самом деле у меня всё гораздо интереснее. Когда более 40 элементов в заданной последовательности изменяются, вносить какие-то изменения в скрипт (особенно в самое начало) повлечет за собой кучу проблем.

И всё это нужно повторять после того, как свершится последнее действие.

Скажите пожалуйста, как всё это можно сделать?

Спасибо!

UPD: решение проблемы с учётом ответов и помощи зарубежного комьюнити:

Всё работает как надо, скрипт запускается без задержек.
<div class="block block-1"></div>
<div class="block block-2"></div>
<div class="block block-3"></div>

.block-1 {background: red;}
.block-1.active {height: 100px;}
.block-2 {background: green;}
.block-2.active {height: 100px;}
.block-3 {background: blue;}
.block-3.active {height: 100px;}

.block-1.active {transition: height .5s linear;}
.block-2.active {transition: height .5s linear; transition-delay: .5s;}
.block-3.active {transition: height .5s linear; transition-delay: 1s;}
.block {transition: height 0s linear;}

function animation() {
    $('.block-1').addClass('active');
    $('.block-2').addClass('active');
    $('.block-3').addClass('active');
    setTimeout(function() {
        $('.block-1, .block-2, .block-3').removeClass('active');
    }, 1500);
}

animation();

setInterval(function() {
    animation();
}, 1500);

Оно же на JSFiddle.
  • Вопрос задан
  • 2389 просмотров
Подписаться 1 Оценить Комментировать
Ответ пользователя Андрей К ответам на вопрос (4)
standy
@standy
jquery в плане сложной асинхронной логики это плохой помощник, смотрите в сторону promises

Подождать 500мс можно так:
setTimeOut(function() {
  $('.block-2').addClass('active');
  // тут запускаете следующее ожидание
}, 500)
Ответ написан
Комментировать