@Rasko338

Почему не останавливается таймер в плагине?

Появилась необходимость написать плагин на jQuery, но я в js абсолютный новичок.
Суть плагина: с определенной периодичностью собираются данные о положении курсора и времени, которое он там находится. И так же с определенной периодичностью отправляются ajax-запросы на сервер. Положение курсора рассчитывается относительно объекта.
Написал плагин, но он корректно работает только с одним объектом, иначе он может сломаться.
Пример
Если навести курсор на '#test2', то таймеры уже не остановятся. Как исправить понятия не имею.

;(function ($) {

  var defaultOptions = {
    checkInterval: 30,
    sendInterval: 3000,
    url: ''
  };

  $.fn.trackCoords = function (option) {
    var options = $.extend({}, defaultOptions, option),
        element = this,
        checkTimerId,
        sendTimerId;
    
    element.mouseover(function (event) {
      // здесь собираются данные
      checkTimerId = setInterval(function() {
        /* ... */
      }, options.checkInterval);

      // здесь отправляются ajax-запросом
      sendTimerId = setInterval(function () {
        /* ... */
      }, options.sendInterval);
    });

    // если курсор не наведен на объект таймеры удаляются
    element.mouseout(function () {
      clearInterval(checkTimerId);
      clearInterval(sendTimerId);
    });

    return element;
  };

}(jQuery));
  • Вопрос задан
  • 117 просмотров
Решения вопроса 1
0xD34F
@0xD34F Куратор тега JavaScript
Сейчас у вас checkTimerId и sendTimerId существуют в единственных экземплярах - одни на все элементы, содержащиеся в наборе, на который ссылается this в trackCoords. События, по которым устанавливаются/снимаются интервалы всплывают, а элементы вложены один в другой - так что когда курсор уходит с внешнего элемента на внутренний, то сначала снимаются интервалы внешнего элемента, затем устанавливаются интервалы внутреннего элемента, затем событие mouseover, случившееся на внутреннем элементе достигает внешнего, и там опять устанавливаются интервалы, при этом идентификаторы интервалов внутреннего элемента затираются, после чего снять их уже нельзя.

Так что, во-первых, элементы надо обрабатывать независимо:

$.fn.trackCoords = function(options) {
  return this.each(function() {
    const $element = $(this);
    // ...
  });
};

Во-вторых, не надо на одних элементах обрабатывать события, которые приходят от других - останавливайте всплытие событий, или проверяйте, откуда пришло событие, сравнивая целевой элемент с тем, к которому прицеплен обработчик:

$element.mouseover(function(e) {
  if (this !== e.target) {
    // чужое событие - не интересно, не обрабатываем
    return;
  }
 
  // ...
});

Кроме того, устанавливать обработчик события mousemove внутри обработчика mouseover - сомнительная затея. При каждом наведении курсора на элемент устанавливается новый обработчик, зачем это? Установите его один раз, там же, где устанавливаются обработчики mouseover/mouseout.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы