Javascript.RU

Создать новую тему Ответ
 
Опции темы Искать в теме
  #1 (permalink)  
Старый 02.03.2020, 14:21
Интересующийся
Отправить личное сообщение для imhateb Посмотреть профиль Найти все сообщения от imhateb
 
Регистрация: 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]);
});


Но тоже никаких результатов. ((( Листание так и не останавливается при наведении. И я даже не знаю, запустилось ли бы оно если бы остановилось.

Кароче я уже обессилен. Понимаю, что вроде задача простая, а я не могу её решить. От этого грустно. Но надо что-то решать, ибо работа стоит.
Ответить с цитированием
  #2 (permalink)  
Старый 02.03.2020, 15:16
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,706

Используете более осмысленные названия переменных, не стал разбираться, что у вас в коде происходит.

Пример управляемого интервала:
<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>
Ответить с цитированием
  #3 (permalink)  
Старый 02.03.2020, 15:31
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

смена блоков с паузой при наведении курсора на родителя
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>
Ответить с цитированием
  #4 (permalink)  
Старый 02.03.2020, 15:56
Интересующийся
Отправить личное сообщение для imhateb Посмотреть профиль Найти все сообщения от imhateb
 
Регистрация: 16.09.2013
Сообщений: 28

рони,
Спасибо большое. Это действительно то что нужно. Почти.

Подскажите пожалуйста, как написать, чтобы вот тут
const len = children.length;

cчитались только дети с классом .banner?

Просто внутри блока .banners есть ещё два блока (со стрелочками) и их учитывать не надо.

Сейчас у меня после последнего баннера показывается пустой блок.

Последний раз редактировалось imhateb, 02.03.2020 в 16:08.
Ответить с цитированием
  #5 (permalink)  
Старый 02.03.2020, 16:11
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

imhateb,
const children  = banner.querySelectorAll(".banner");
       const len = children.length;
       let index = [...children].indexOf(banner.querySelector(".visible")|| children[len - 1]);
Ответить с цитированием
  #6 (permalink)  
Старый 02.03.2020, 16:16
Интересующийся
Отправить личное сообщение для imhateb Посмотреть профиль Найти все сообщения от imhateb
 
Регистрация: 16.09.2013
Сообщений: 28

рони, спасибо. Я уже разобрался кажись))
Сделал вот так:
const children  = banner.getElementsByClassName('banner');
const len = children.length;


И всё заработало как надо.

рони, огромное Вам спасибо за помощь. Даже не знаю как выразить свою признательность. Вы супер!
Ответить с цитированием
  #7 (permalink)  
Старый 02.03.2020, 16:58
Интересующийся
Отправить личное сообщение для imhateb Посмотреть профиль Найти все сообщения от imhateb
 
Регистрация: 16.09.2013
Сообщений: 28

Эмм, рони, неловко так. Только заметил, что не совсем всё гладко получилось.

При наведении мыши баннеры останавливаются - с этим Ок.

Но вот при mouseleave сразу происходит смена баннера - моментально. А должен запуститься интервал. Потому как на сайте эта резкая смена баннеров при отводе мышки смотрится очень убого и совсем не так как надо.

Я попробовал сделать вот так: вместо
banner.addEventListener("mouseleave", showItem.bind(null, banner));

написал
banner.addEventListener("mouseleave", function(){setTimeout(showItem.bind(null, banner), pause) });

Это вроде бы помогло, и после mouseleave баннер меняется не сразу, а с нужной задержкой. Т.е. то что я и хотел.

Но тут вылезла другая проблема. Если несколько раз быстро подёргать мышку на блок с баннерами и обратно, то происходит лютая дичь. Спустя установленный интервал баннеры начинают очень быстро сменяться кратно количеству зафиксированных mouseenter'ов.

Как это победить? Баннеры у меня не картинки, а блоки с текстом и ссылками. Допускаю, что подобные сценарии с многократным попаданием мыши на баннер будут весьма частым явлением.
Ответить с цитированием
  #8 (permalink)  
Старый 02.03.2020, 17:12
Аватар для рони
Профессор
Отправить личное сообщение для рони Посмотреть профиль Найти все сообщения от рони
 
Регистрация: 27.05.2010
Сообщений: 33,064

imhateb,
banner.addEventListener("mouseleave", () => {
 pauseItem(banner);
 banner.timer = setTimeout(showItem.bind(null, banner), pause)
 });

Последний раз редактировалось рони, 02.03.2020 в 17:18. Причина: pauseItem добавил
Ответить с цитированием
  #9 (permalink)  
Старый 02.03.2020, 17:18
Интересующийся
Отправить личное сообщение для imhateb Посмотреть профиль Найти все сообщения от imhateb
 
Регистрация: 16.09.2013
Сообщений: 28

рони, хочется Вас расцеловать. Спасибо огромнейшее!
Ответить с цитированием
  #10 (permalink)  
Старый 03.03.2020, 01:50
Профессор
Отправить личное сообщение для Nexus Посмотреть профиль Найти все сообщения от Nexus
 
Регистрация: 04.12.2012
Сообщений: 3,706

<!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>
Ответить с цитированием
Ответ



Опции темы Искать в теме
Искать в теме:

Расширенный поиск


Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Разработка, хранение, сборка, тестирование нескольких проектов из одного окружения XAPuTOH ExtJS 2 24.07.2018 06:04
Обработка click одного из элементов nooclik jQuery 4 25.06.2018 08:51
как с помощью javascript взять данные из одного файла html и закинуть в другой? rusik Общие вопросы Javascript 10 08.08.2016 12:11
Перезапуск одного таймера из нескольких Drugpunker Элементы интерфейса 16 16.06.2014 14:31
Прогресс бар для загрузки нескольких файлов через XHR Ваяс AJAX и COMET 0 04.12.2013 13:03