В интерактивных веб-картах события играют ключевую роль. Щелчки мышью, перемещение карты, изменение масштаба, загрузка слоёв и множество других действий позволяют создавать динамическое поведение приложения. Однако обработчики событий не всегда должны существовать на протяжении всего жизненного цикла объекта. Во многих сценариях возникает необходимость отключать ранее зарегистрированные обработчики.
Удаление обработчиков позволяет:
В Leaflet все объекты, поддерживающие события, наследуют возможности
работы с ними через механизм Evented.
off()Основным способом удаления обработчиков является метод
off().
Общая форма:
object.off(eventName, handler);
где:
eventName — название события;handler — функция-обработчик, которая была
зарегистрирована ранее.Пример регистрации и последующего удаления:
function onMapClick(event) {
console.log(event.latlng);
}
map.on('click', onMapClick);
map.off('click', onMapClick);
После вызова off() обработчик больше не будет
реагировать на щелчки по карте.
Наиболее распространённая ошибка при удалении обработчиков связана с использованием анонимных функций.
Неправильный вариант:
map.on('click', function(event) {
console.log(event.latlng);
});
map.off('click', function(event) {
console.log(event.latlng);
});
Удаление не произойдёт, поскольку при каждом создании функции формируется новый объект функции.
Leaflet сравнивает ссылки на функции, а не их содержимое.
Правильный вариант:
function handleClick(event) {
console.log(event.latlng);
}
map.on('click', handleClick);
map.off('click', handleClick);
Одна функция может быть зарегистрирована для нескольких событий.
function updateInfo() {
console.log('Обновление');
}
map.on('zoomend', updateInfo);
map.on('moveend', updateInfo);
Удаление выполняется отдельно для каждого события:
map.off('zoomend', updateInfo);
map.off('moveend', updateInfo);
После этого функция перестанет вызываться при масштабировании и перемещении карты.
Если требуется удалить все подписки определённого типа, можно передать только имя события.
map.off('click');
После выполнения будут удалены все обработчики события
click, независимо от того, сколько их было
зарегистрировано.
Пример:
map.on('click', handler1);
map.on('click', handler2);
map.on('click', handler3);
map.off('click');
Все три обработчика будут удалены.
Метод off() без параметров удаляет абсолютно все события
объекта.
map.off();
После этого карта больше не будет содержать зарегистрированных пользовательских обработчиков.
Подобный вызов следует использовать осторожно, особенно в крупных приложениях, где различные модули могут подписываться на события независимо друг от друга.
События существуют не только у карты, но и у слоёв.
Например:
const marker = L.marker([55.751244, 37.618423]).addTo(map);
function markerClick() {
console.log('Маркер нажат');
}
marker.on('click', markerClick);
Удаление:
marker.off('click', markerClick);
Теперь нажатие на маркер больше не вызывает функцию.
Пример для полигона:
const polygon = L.polygon([
[55.75, 37.61],
[55.76, 37.64],
[55.73, 37.65]
]).addTo(map);
function highlight() {
polygon.setStyle({
color: 'red'
});
}
polygon.on('mouseover', highlight);
Отключение:
polygon.off('mouseover', highlight);
События доступны и для всплывающих окон.
function popupOpened() {
console.log('Окно открыто');
}
map.on('popupopen', popupOpened);
Удаление:
map.off('popupopen', popupOpened);
После удаления обработчик больше не будет реагировать на открытие всплывающих окон.
Leaflet позволяет указывать контекст выполнения функции.
Регистрация:
const controller = {
name: 'MapController',
handleClick() {
console.log(this.name);
}
};
map.on('click', controller.handleClick, controller);
Удаление должно использовать тот же контекст:
map.off('click', controller.handleClick, controller);
Если контекст отличается, удаление может не сработать.
Иногда требуется самостоятельно удалить обработчик после первого вызова.
function firstClick(event) {
console.log(event.latlng);
map.off('click', firstClick);
}
map.on('click', firstClick);
После первого клика подписка исчезнет.
Однако для таких случаев существует более удобный механизм
once(), который автоматически удаляет обработчик после
выполнения.
map.once('click', function(event) {
console.log(event.latlng);
});
При работе с динамическими слоями рекомендуется удалять подписки перед уничтожением объектов.
Пример:
function markerHandler() {
console.log('Click');
}
marker.on('click', markerHandler);
marker.off('click', markerHandler);
map.removeLayer(marker);
Такой подход предотвращает появление «висячих» ссылок и упрощает сопровождение кода.
Часто карта работает в нескольких режимах.
Например, режим просмотра:
function showInfo(event) {
console.log(event.latlng);
}
map.on('click', showInfo);
Затем пользователь включает режим рисования.
Перед активацией нового режима старые обработчики отключаются:
map.off('click', showInfo);
После этого подключается новая логика:
function drawPoint(event) {
L.marker(event.latlng).addTo(map);
}
map.on('click', drawPoint);
Такой подход предотвращает конфликт различных сценариев работы.
Leaflet позволяет регистрировать сразу несколько событий.
function zoomHandler() {
console.log('Zoom');
}
function moveHandler() {
console.log('Move');
}
map.on({
zoomend: zoomHandler,
moveend: moveHandler
});
Удаление возможно аналогичным образом:
map.off({
zoomend: zoomHandler,
moveend: moveHandler
});
Это удобно при большом количестве подписок.
Для диагностики можно использовать метод listens().
if (map.listens('click')) {
console.log('Есть обработчики');
}
После удаления:
map.off('click');
результат проверки изменится:
console.log(map.listens('click'));
Метод помогает контролировать состояние событий в сложных приложениях.
map.on('click', function() {
console.log('Click');
});
Позже удалить такой обработчик невозможно без сохранённой ссылки.
Лучше:
const clickHandler = function() {
console.log('Click');
};
map.on('click', clickHandler);
function update() {
console.log('Update');
}
map.on('zoomend', update);
map.on('zoomend', update);
Функция будет вызвана дважды.
Для предотвращения подобных ситуаций перед повторной регистрацией нередко выполняют удаление:
map.off('zoomend', update);
map.on('zoomend', update);
Иногда используется:
map.off();
Такой вызов может отключить обработчики, зарегистрированные другими модулями приложения.
В крупных проектах предпочтительнее удалять только конкретные подписки.
function inspectLocation(event) {
console.log(
event.latlng.lat,
event.latlng.lng
);
}
function createMarker(event) {
L.marker(event.latlng).addTo(map);
}
function enableInspectMode() {
map.off('click', createMarker);
map.on('click', inspectLocation);
}
function enableDrawMode() {
map.off('click', inspectLocation);
map.on('click', createMarker);
}
В данном примере карта работает в двух режимах:
При переключении режимов старые обработчики удаляются, а новые
подключаются. Такой механизм является одним из наиболее распространённых
сценариев применения метода off() в приложениях на основе
Leaflet.
const handlers = {
click: onClick,
zoom: onZoom
};
Это значительно упрощает последующее удаление.
map.off('click', onClick);
map.off('zoomend', onZoom);
Особенно важно для приложений на React, Vue и Angular.
once() для одноразовых действийmap.once('load', initData);
Автоматическое удаление уменьшает количество служебного кода.
Вместо:
map.off();
предпочтительнее:
map.off('click', onClick);
map.off('zoomend', onZoom);
Такой подход делает систему событий предсказуемой, облегчает сопровождение приложения и снижает вероятность появления труднообнаружимых ошибок.