Leaflet реализует событийную модель поверх объектов карты, слоёв и всплывающих окон, где popup рассматривается как полноценный интерактивный компонент с жизненным циклом. События popup возникают при открытии, закрытии и обновлении всплывающих окон, а также при их привязке к слоям. Эти события позволяют синхронизировать UI, управлять состоянием интерфейса и строить сложные сценарии взаимодействия с картой.
Основные события, связанные с всплывающими окнами, концентрируются вокруг их жизненного цикла:
Эти события доступны как на уровне карты, так и на уровне слоёв, в зависимости от того, где был инициирован popup.
Пример регистрации обработчиков на карте:
map.on('popupopen', function (e) {
console.log('Popup открыт');
console.log(e.popup);
console.log(e.popup._source);
});
map.on('popupclose', function (e) {
console.log('Popup закрыт');
});
Объект события e содержит ссылку на сам popup, а также
на источник, если popup был привязан к слою (marker, polygon и т.д.).
Это позволяет отслеживать, какой именно объект карты инициировал
всплывающее окно.
События popup передают унифицированный объект, в котором ключевую роль играют следующие поля:
Пример использования координат:
map.on('popupopen', function (e) {
if (e.popup && e.popup.getLatLng) {
const coords = e.popup.getLatLng();
console.log('Popup открыт в точке:', coords);
}
});
Наличие latlng зависит от типа popup: он может быть
привязан как к географической точке, так и к DOM-элементу без
координат.
Popup чаще всего создаётся через привязку к слою:
marker.bindPopup('Информация об объекте');
В этом случае событие popupopen срабатывает не только на
карте, но и на уровне слоя:
marker.on('popupopen', function (e) {
console.log('Popup открыт для маркера');
});
Такой подход позволяет локализовать логику обработки внутри конкретного объекта карты, не перегружая глобальные обработчики.
При этом один и тот же popup может инициировать события на нескольких уровнях:
При открытии popup происходит последовательность действий:
popupopen на слоеpopupopen на картеКонтекст this внутри обработчиков зависит от способа
подписки:
map.on('popupopen', function (e) {
console.log(this === map); // true
});
При обработке на уровне слоя:
marker.on('popupopen', function (e) {
console.log(this === marker); // true
});
Событие закрытия popup срабатывает при:
map.closePopup()map.on('popupclose', function (e) {
console.log('Закрыт popup:', e.popup);
});
Важно учитывать, что после popupclose DOM-элемент может
быть удалён или переиспользован, поэтому прямые ссылки на внутренние
элементы popup становятся невалидными.
Popup может быть открыт программно, и это также инициирует события:
marker.openPopup();
При этом popupopen сработает аналогично
пользовательскому открытию. Это позволяет унифицировать обработку вне
зависимости от источника действия.
Распространённый паттерн — блокировка повторного открытия:
map.on('popupopen', function (e) {
if (e.popup && e.popup._alreadyHandled) return;
e.popup._alreadyHandled = true;
});
События popup участвуют в механизме всплытия событий карты. Если popup открыт на маркере, событие проходит цепочку:
marker → layer → map
Это позволяет централизованно перехватывать события:
map.on('popupopen', function (e) {
console.log('Глобальный обработчик popup');
});
Однако при этом важно учитывать дублирование логики: один и тот же popup может быть обработан на нескольких уровнях, если подписки не разделены.
При изменении содержимого popup часто используется сочетание событий и методов обновления:
map.on('popupopen', function (e) {
const popup = e.popup;
popup.setContent('Загрузка данных...');
setTimeout(() => {
popup.setContent('Обновлённые данные');
}, 1000);
});
Такой подход используется для асинхронной подгрузки данных, когда popup уже отображён, но контент ещё формируется.
По умолчанию карта может отображать только один активный popup. При открытии нового:
popupclosepopupopen для новогоЭто создаёт каскад событий:
map.on('popupclose', function () {
console.log('Закрыт предыдущий popup');
});
map.on('popupopen', function () {
console.log('Открыт новый popup');
});
При кастомной логике управления popup важно учитывать этот порядок, особенно при синхронизации состояния интерфейса.
Popup влияет на поведение карты в части обработки событий взаимодействия:
События popup часто используются совместно с:
moveendzoomendclickПример синхронизации:
map.on('popupopen', function (e) {
map.panTo(e.popup.getLatLng());
});
Некоторые сценарии требуют контроля над автоматическим открытием popup:
marker.on('click', function (e) {
e.originalEvent.preventDefault();
marker.openPopup();
});
Хотя popup и управляется Leaflet автоматически при
bindPopup, обработчики событий позволяют переопределить
стандартное поведение и внедрить собственную логику условий
открытия.
При создании кастомных popup через L.popup() события
работают аналогично, но:
const popup = L.popup()
.setLatLng([51.5, -0.09])
.setContent('Кастомный popup');
map.on('popupopen', function (e) {
console.log('Открыт кастомный popup');
});