02.03.2020, 14:21
|
Интересующийся
|
|
Регистрация: 16.09.2013
Сообщений: 28
|
|
Остановка одного из нескольких интервалов
Здравствуйте. Помогите пожалуйста. Обидно осознавать, но похоже своим мозгом я это уже не осилю. Всю ночь потратил на попытки .
На странице имеется три блока с баннерами (.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]);
});
Но тоже никаких результатов. ((( Листание так и не останавливается при наведении. И я даже не знаю, запустилось ли бы оно если бы остановилось.
Кароче я уже обессилен. Понимаю, что вроде задача простая, а я не могу её решить. От этого грустно. Но надо что-то решать, ибо работа стоит.
|
|
02.03.2020, 15:16
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,795
|
|
Используете более осмысленные названия переменных, не стал разбираться, что у вас в коде происходит.
Пример управляемого интервала:
<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>
|
|
02.03.2020, 15:31
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,126
|
|
смена блоков с паузой при наведении курсора на родителя
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>
|
|
02.03.2020, 15:56
|
Интересующийся
|
|
Регистрация: 16.09.2013
Сообщений: 28
|
|
рони,
Спасибо большое. Это действительно то что нужно. Почти.
Подскажите пожалуйста, как написать, чтобы вот тут
const len = children.length;
cчитались только дети с классом .banner?
Просто внутри блока .banners есть ещё два блока (со стрелочками) и их учитывать не надо.
Сейчас у меня после последнего баннера показывается пустой блок.
Последний раз редактировалось imhateb, 02.03.2020 в 16:08.
|
|
02.03.2020, 16:11
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,126
|
|
imhateb,
const children = banner.querySelectorAll(".banner");
const len = children.length;
let index = [...children].indexOf(banner.querySelector(".visible")|| children[len - 1]);
|
|
02.03.2020, 16:16
|
Интересующийся
|
|
Регистрация: 16.09.2013
Сообщений: 28
|
|
рони, спасибо. Я уже разобрался кажись))
Сделал вот так:
const children = banner.getElementsByClassName('banner');
const len = children.length;
И всё заработало как надо.
рони, огромное Вам спасибо за помощь. Даже не знаю как выразить свою признательность. Вы супер!
|
|
02.03.2020, 16:58
|
Интересующийся
|
|
Регистрация: 16.09.2013
Сообщений: 28
|
|
Эмм, рони, неловко так. Только заметил, что не совсем всё гладко получилось.
При наведении мыши баннеры останавливаются - с этим Ок.
Но вот при mouseleave сразу происходит смена баннера - моментально. А должен запуститься интервал. Потому как на сайте эта резкая смена баннеров при отводе мышки смотрится очень убого и совсем не так как надо.
Я попробовал сделать вот так: вместо
banner.addEventListener("mouseleave", showItem.bind(null, banner));
написал
banner.addEventListener("mouseleave", function(){setTimeout(showItem.bind(null, banner), pause) });
Это вроде бы помогло, и после mouseleave баннер меняется не сразу, а с нужной задержкой. Т.е. то что я и хотел.
Но тут вылезла другая проблема. Если несколько раз быстро подёргать мышку на блок с баннерами и обратно, то происходит лютая дичь. Спустя установленный интервал баннеры начинают очень быстро сменяться кратно количеству зафиксированных mouseenter'ов.
Как это победить? Баннеры у меня не картинки, а блоки с текстом и ссылками. Допускаю, что подобные сценарии с многократным попаданием мыши на баннер будут весьма частым явлением.
|
|
02.03.2020, 17:12
|
|
Профессор
|
|
Регистрация: 27.05.2010
Сообщений: 33,126
|
|
imhateb,
banner.addEventListener("mouseleave", () => {
pauseItem(banner);
banner.timer = setTimeout(showItem.bind(null, banner), pause)
});
Последний раз редактировалось рони, 02.03.2020 в 17:18.
Причина: pauseItem добавил
|
|
02.03.2020, 17:18
|
Интересующийся
|
|
Регистрация: 16.09.2013
Сообщений: 28
|
|
рони, хочется Вас расцеловать. Спасибо огромнейшее!
|
|
03.03.2020, 01:50
|
Профессор
|
|
Регистрация: 04.12.2012
Сообщений: 3,795
|
|
<!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>
|
|
|
|