Javascript бегущий огонек
Понадобилось мне на днях сделать "бегущий огонек" на javascript, без jQuery и каких - либо зависимостей. После недолгого поиска в интернете решил сделать сам. Получился некий цикличный итератор над коллекцией DOM-элементов с таймаутом. Кому нужно - забирайте.
Так же было решено вынести всю специфику в клиентский код, потому как может кому то понадобится эффект не именно бегущий огонек, а допустим какой другой цикличный эффект над набором DOM-элементов, например подпрыгивание чего - либо или появление или исчезание, или любая другая логика, укладывающаяся в схему:
while true: берем следующий элемент; если элементов больше нет - берем первый элемент; применяем к элементу первую ф-цию; ждем таймаут; применяем к элементу вторую ф-цию; ждем таймаут; endwhile;
В общем оставил чисто абстракцию, реализующую задачу описанную выше, но для примера "бегущий огонек" подойдет как раз кстати. В примере клиентские функции при вызове будут просто делать: одна - устанавливать класс lightOn, а вторая - убирать этот класс у текущего элемента. Так мы добьемся эффекта "бегущий огонек".
Бегущий огонек демо
Бегущий огонек код
"use strict"; /** * Цикличный итератор с временной задержкой. * * @param {NodeList|HTMLElement[]} oNodeList - массив или NodeList элементов * над которыми нужно циклично применять функции callbackStart и callbackEnd * @param {Function} callbackStart - функция обр. вызова, вызываемая при * переходе на элемент, получит текущий элемнт как параметр. * @param {Function} callbackEnd - функция обр. вызова, вызываемая при * уходе с элемента, получит текущий элемнт как параметр. * @param {number} speed - временная задержка в мсек. */ function TimeoutIterator(oNodeList, callbackStart, callbackEnd, speed) { var _index = 0, _interval = 0; // Предохранитель от возможного вызова без "new" if (!(this instanceof TimeoutIterator.prototype.constructor)) { return new TimeoutIterator(oNodeList, callbackStart, callbackEnd, speed); } /** * Стартовая операция. * * Её предназначение вызвать или не вызвать 1-й коллбэк (callbackStart), * а затем спустя заданный интервал (speed) вызвать финишную операцию. * * @param {HTMLElement} element - текущий элемент набора */ function startAction(element) { // если передан первый коллбэк - вызываем его: callbackStart && callbackStart(element); // с указанной задержкой... window.setTimeout(function () { // вызываем вторую операцию. stopAction(element); }, speed); } /** * Финишная операция. * * Её предназначение вызвать или не вызвать 2-й коллбэк (callbackEnd). * * @param {HTMLElement} element - текущий элемент набора */ function stopAction(element) { callbackEnd && callbackEnd(element); } /** * Запустить. */ this.run = function () { // Предохранитель от повторного запуска // уже работающего экземпляра. if (_interval > 0) { return; } _interval = window.setInterval(function () { // Для "удержания" индекса текущего элемента // в пределах размера oNodeList применяем // операцию деления по модулю. _index %= oNodeList.length; // Запускаем стартовую операцию: startAction(oNodeList[_index]); _index++; }, speed); }; /** * Остановить. */ this.stop = function () { // Просто очистим _interval window.clearInterval(_interval); _interval = 0; }; }
Использование "бегущий огонек"
Под "бегущий огонек" нам понадобится примерно следующая разметка:
<p> <button id="runner" type="button">СТАРТ</button> <button id="stop" type="button">СТОП</button> </p> <div id="iter-container"> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> <div class="light"></div> </div>
А сам скрипт вызываем следующим образом:
/** @type {NodeList} elementCollection - набор элементов для "бегущего огонька" */ var elementCollection = document.getElementById("iter-container") .getElementsByTagName("DIV"), lr = TimeoutIterator( elementCollection, /** * стартовая ф-ция: просто устанвливает имя класса lightOn * @param {HTMLElement} element - текущий элемент набора */ function (element) { element.className += (element.className.length) ? " lightOn" : "lightOn"; }, /** * финишная ф-ция: просто убирает имя класса lightOn * @param {HTMLElement} element - текущий элемент набора */ function (element) { element.className = element.className.replace(/\s?lightOn/, ""); }, /* задержка в мсек. */ 50 ); /* "Вешаем" обработчик для запуска действия */ document.getElementById("runner").onclick = function () { lr.run(); }; /* "Вешаем" обработчик для остановки действия */ document.getElementById("stop").onclick = function () { lr.stop(); };
Информация копипастерам
Внимание! Копирование контента с сайта, возможно только с разрешения администратора. Т.е. Меня! Я скорее всего разрешу Вам это сделать, в обмен на живую ссылку, на статью оригинал.