Отмена подписки на события

В SVG.js события играют ключевую роль в интерактивных приложениях, позволяя реагировать на действия пользователя, изменения состояния элементов или временные триггеры. Управление подписками на события включает не только их добавление, но и корректное удаление, чтобы избежать утечек памяти и конфликтов между обработчиками.


Подписка на события

Для начала рассмотрим стандартный способ подписки:

const draw = SVG().addTo('body').size(300, 300);
const rect = draw.rect(100, 100).fill('blue');

function handleClick(event) {
  console.log('Клик по прямоугольнику', event);
}

rect.on('click', handleClick);

Здесь метод on добавляет обработчик handleClick к событию click. Важно, что каждый вызов on создаёт отдельную ссылку на обработчик, которую можно использовать для последующего удаления.


Отмена подписки через off

Метод off используется для удаления обработчиков событий. Он поддерживает несколько вариантов применения:

  1. Удаление конкретного обработчика по событию:
rect.off('click', handleClick);

После выполнения этой команды клик по прямоугольнику больше не будет вызывать handleClick. Если к событию было привязано несколько функций, остальные останутся активными.

  1. Удаление всех обработчиков для конкретного события:
rect.off('click');

Все функции, подписанные на событие click для данного элемента, будут отменены. Этот способ полезен, когда необходимо полностью очистить обработчики перед изменением состояния элемента.

  1. Удаление всех обработчиков на элементе:
rect.off();

Метод без аргументов снимает все подписки на все события, зарегистрированные через SVG.js для данного элемента. Следует использовать осторожно, чтобы случайно не удалить важные обработчики.


Специфические сценарии

Подписка на событие с именованной функцией

Использование анонимной функции затрудняет отмену подписки:

rect.on('mouseover', function(e) {
  console.log('Наведение мыши');
});

// Такой обработчик удалить через off невозможно напрямую
rect.off('mouseover'); // удалит все обработчики mouseover

Для точного удаления необходимо использовать именованную функцию:

function handleMouseOver(e) {
  console.log('Наведение мыши');
}

rect.on('mouseover', handleMouseOver);
rect.off('mouseover', handleMouseOver);

Подписка на несколько событий одновременно

Метод on поддерживает массив событий:

function logEvent(e) { console.log(e.type); }

rect.on(['mouseenter', 'mouseleave'], logEvent);

Удаление конкретного обработчика выполняется аналогично:

rect.off(['mouseenter', 'mouseleave'], logEvent);

Подписки на дочерние элементы и делегирование

SVG.js позволяет работать с группами элементов (<g>). Подписка на событие группы не распространяется автоматически на дочерние элементы. Если требуется делегирование, следует подписываться на каждый элемент индивидуально. Отмена подписки также производится на конкретном элементе.

const group = draw.group();
const circle = group.circle(50).fill('red');

circle.on('click', handleClick);
circle.off('click', handleClick);

Важные моменты при работе с off

  • off работает только с обработчиками, добавленными через on. События, назначенные через нативный addEventListener, не будут сняты этим методом.
  • Для предотвращения утечек памяти необходимо удалять обработчики при удалении элементов из DOM:
rect.remove();
rect.off(); // очистка всех подписок
  • Метод off возвращает сам элемент, что позволяет использовать цепочку вызовов:
rect.off('click', handleClick).fill('green').stroke({ width: 2 });

Применение в динамических интерфейсах

В интерфейсах, где элементы создаются и уничтожаются динамически, правильное управление подписками критично. Часто используют шаблон добавления обработчиков при создании элемента и их удаления перед удалением элемента. Это гарантирует отсутствие “висячих” обработчиков, которые могут приводить к неожиданным ошибкам.

function createButton(label) {
  const btn = draw.rect(100, 50).fill('orange');
  function onClick() { console.log(label); }
  
  btn.on('click', onClick);
  
  btn.removeWithEvents = () => {
    btn.off('click', onClick);
    btn.remove();
  }
  
  return btn;
}

const myButton = createButton('Test');
myButton.removeWithEvents(); // безопасное удаление

SVG.js предоставляет гибкий и безопасный механизм управления событиями через on и off. Чёткое понимание этих методов позволяет строить динамичные, интерактивные графические интерфейсы без риска утечек памяти и конфликтов обработчиков.