Остановка одного из нескольких интервалов
Здравствуйте. Помогите пожалуйста. Обидно осознавать, но похоже своим мозгом я это уже не осилю. Всю ночь потратил на попытки :cray: .
На странице имеется три блока с баннерами (.banners). Хочу добавить автолисталку для них, чтобы они менялись через определённый интервал. Делаю вот так: var interval, timer = 1000; function startInterval(e) { var cur = parseInt(e.find('.banner.visible').attr('id').replace(/\D+/g,"")); var col = e.find('.banner').length; interval = setInterval(function(){ if (cur < col) {cur++} else {cur = 1} e.find('.banner').removeClass('visible'); e.find('.banner#banner'+cur).addClass('visible'); },timer); }; $('.banners').each(function(){startInterval($(this));}); Всё круто, всё листается. Но мне нужно сделать, чтобы при наведении мыши это перелистывание останавливалось в соответствующем блоке с баннерами. И соответственно запускалось когда мышки на баннере нет. Этот код не помогает в этом ( $('.banners').mouseenter(function(){clearInterval(interval);}); $('.banners').mouseleave(function(){startInterval();}); Ну тут понятно, что он запуститься не сможет, так как не ясно к какому блоку баннеров относится startInterval(); после mouseleave. Но оно даже не останавливается при mouseenter и clearInterval не срабатывает. Подумал, что в коде непонятно какой именно интервал останавливать. Стал копать в сторону идентификации интервалов, чтобы при попытке остановки обращаться более адресно. Намутил вот такое: var interval = [], timer = 1000; function startInterval(e,i) { var cur = parseInt(e.find('.banner.visible').attr('id').replace(/\D+/g,"")); var col = e.find('.banner').length; i = setInterval(function(){ if (cur < col) {cur++} else {cur = 1} e.find('.banner').removeClass('visible'); e.find('.banner#banner'+cur).addClass('visible'); },timer); }; for(var i = 0; i < $('.banners').length; i++) { interval[i] = 'interval'+i; $('.banners').eq(i).attr('data',i); startInterval($('.banners').eq(i),interval[i]); } $('.banners').mouseenter(function(){ var i = $(this).attr('data'); clearInterval(interval[i]); }); $('.banners').mouseleave(function(){ var i = $(this).attr('data'); startInterval($(this),interval[i]); }); Но тоже никаких результатов. ((( Листание так и не останавливается при наведении. И я даже не знаю, запустилось ли бы оно если бы остановилось. Кароче я уже обессилен. Понимаю, что вроде задача простая, а я не могу её решить. От этого грустно. Но надо что-то решать, ибо работа стоит. |
Используете более осмысленные названия переменных, не стал разбираться, что у вас в коде происходит.
Пример управляемого интервала: <div><input type="number" readonly value="0"/></div> <button type="button" data-action="pause">Pause</button> <button type="button" data-action="resume">Resume</button> <button type="button" data-action="destroy">Destroy</button> <script> var controlledInterval = function (callback, delay) { var args = [].slice.call(arguments, 2); var stepsPerLoop = 50, loopDelay = delay / stepsPerLoop, counter = 0, pause = false, timeout; timeout = setTimeout(function tik() { if (!pause) { counter += loopDelay; } if (counter >= delay) { callback.apply(window, args); counter = 0; } timeout = setTimeout(tik, loopDelay); }, loopDelay); return { pause: function () { pause = true; }, resume: function () { pause = false; }, destroy: function () { clearTimeout(timeout); } }; }; var input = document.querySelector('input'), interval = controlledInterval(function () { input.value = +input.value + 1; }, 1000); document.querySelectorAll('[data-action]').forEach(function (node) { node.addEventListener('click', function () { interval[this.dataset.action](); }); }); </script> |
смена блоков с паузой при наведении курсора на родителя
imhateb,
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> .banners{ height: 100px; width: 200px; border: 4px solid #FF4500; border-radius: 4px; margin: 10px; } .banners .item{ display: none; height: 100%; } .banners .item.visible{ display: block; } .banners .item:nth-child(1){ background-color: #0000FF; } .banners .item:nth-child(2){ background-color: #FF0000; } .banners .item:nth-child(3){ background-color: #808080; } .banners .item:nth-child(4){ background-color: #FFFF00; } .banners .item:nth-child(5){ background-color: #FF00FF; } </style> <script> document.addEventListener( "DOMContentLoaded" , function() { const pause = 1200; const pauseItem = ({timer}) => clearTimeout(timer); const showItem = banner => { pauseItem(banner); const children = banner.children; const len = children.length; let index = [...children].indexOf(banner.querySelector(".visible")|| banner.lastElementChild); children[index].classList.remove("visible"); index = ++index % len; children[index].classList.add("visible"); banner.timer = setTimeout(showItem.bind(null, banner), pause); }; for( const banner of document.querySelectorAll(".banners")) { banner.addEventListener("mouseleave", showItem.bind(null, banner)); banner.addEventListener("mouseenter", pauseItem.bind(null, banner)); showItem(banner); }; }); </script> </head> <body> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> </body> </html> |
рони,
Спасибо большое. Это действительно то что нужно. Почти. Подскажите пожалуйста, как написать, чтобы вот тут const len = children.length; cчитались только дети с классом .banner? Просто внутри блока .banners есть ещё два блока (со стрелочками) и их учитывать не надо. Сейчас у меня после последнего баннера показывается пустой блок. |
imhateb,
const children = banner.querySelectorAll(".banner"); const len = children.length; let index = [...children].indexOf(banner.querySelector(".visible")|| children[len - 1]); |
рони, спасибо. Я уже разобрался кажись))
Сделал вот так: const children = banner.getElementsByClassName('banner'); const len = children.length; И всё заработало как надо. рони, огромное Вам спасибо за помощь. Даже не знаю как выразить свою признательность. Вы супер! :thanks: |
Эмм, рони, неловко так. Только заметил, что не совсем всё гладко получилось.
При наведении мыши баннеры останавливаются - с этим Ок. Но вот при mouseleave сразу происходит смена баннера - моментально. А должен запуститься интервал. Потому как на сайте эта резкая смена баннеров при отводе мышки смотрится очень убого и совсем не так как надо. Я попробовал сделать вот так: вместо banner.addEventListener("mouseleave", showItem.bind(null, banner)); написал banner.addEventListener("mouseleave", function(){setTimeout(showItem.bind(null, banner), pause) }); Это вроде бы помогло, и после mouseleave баннер меняется не сразу, а с нужной задержкой. Т.е. то что я и хотел. Но тут вылезла другая проблема. Если несколько раз быстро подёргать мышку на блок с баннерами и обратно, то происходит лютая дичь. Спустя установленный интервал баннеры начинают очень быстро сменяться кратно количеству зафиксированных mouseenter'ов. Как это победить? Баннеры у меня не картинки, а блоки с текстом и ссылками. Допускаю, что подобные сценарии с многократным попаданием мыши на баннер будут весьма частым явлением. |
imhateb,
banner.addEventListener("mouseleave", () => { pauseItem(banner); banner.timer = setTimeout(showItem.bind(null, banner), pause) }); |
рони, хочется Вас расцеловать. Спасибо огромнейшее!
|
<!DOCTYPE html> <html> <head> <title>Untitled</title> <meta charset="utf-8"> <style type="text/css"> .banners{ height: 100px; width: 200px; border: 4px solid #FF4500; border-radius: 4px; margin: 10px; } .banners .item{ display: none; height: 100%; } .banners .item.visible{ display: block; } .banners .item:nth-child(1){ background-color: #0000FF; } .banners .item:nth-child(2){ background-color: #FF0000; } .banners .item:nth-child(3){ background-color: #808080; } .banners .item:nth-child(4){ background-color: #FFFF00; } .banners .item:nth-child(5){ background-color: #FF00FF; } </style> <script> document.addEventListener('DOMContentLoaded', function() { var controlledInterval = function(callback, delay) { var args = [].slice.call(arguments, 2); var stepsPerLoop = 50, loopDelay = delay / stepsPerLoop, counter = 0, pause = false, timeout; timeout = setTimeout(function tik() { if (!pause) { counter += loopDelay; } if (counter >= delay) { callback.apply(window, args); counter = 0; } timeout = setTimeout(tik, loopDelay); }, loopDelay); return { pause: function() { pause = true; }, resume: function() { pause = false; }, destroy: function() { clearTimeout(timeout); } }; }; document.querySelectorAll('.banners').forEach(function(container) { var items = container.querySelectorAll('.item'), activeItemIndex = -1; var showNextItem = function() { if (items[activeItemIndex]) { items[activeItemIndex].classList.remove('visible'); } activeItemIndex = ++activeItemIndex % items.length; items[activeItemIndex].classList.add('visible'); }; showNextItem(); var interval = controlledInterval(showNextItem, 1000); container.addEventListener('mouseenter', interval.pause); container.addEventListener('mouseleave', interval.resume); }); }); </script> </head> <body> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> <div class="banners"> <div class="item">01</div> <div class="item">02</div> <div class="item">03</div> <div class="item">04</div> <div class="item">05</div> </div> </body> </html> |
Часовой пояс GMT +3, время: 16:36. |