Библиотека Masonry активно использует событийную модель для уведомления кода приложения о завершении различных внутренних процессов: построения сетки, перерасчёта позиций элементов, добавления новых карточек и других операций.
События позволяют синхронизировать интерфейс с процессом компоновки. Например:
Подписка на события выполняется через метод on, а
прекращение отслеживания — через метод off.
Корректная отписка от событий является важной частью архитектуры приложения. Она предотвращает утечки памяти, некорректное выполнение обработчиков и накопление лишних подписок при повторной инициализации компонентов.
Перед рассмотрением отписки необходимо понимать механизм регистрации обработчиков.
Синтаксис подписки:
masonryInstance.on(eventName, listener)
Где:
eventName — имя событияlistener — функция-обработчикПример:
var grid = document.querySelector('.grid');
var msnry = new Masonry(grid, {
itemSelector: '.grid-item',
columnWidth: 200
});
function onLayoutComplete(items) {
console.log('Layout finished:', items.length);
}
msnry.on('layoutComplete', onLayoutComplete);
После завершения компоновки Masonry вызовет функцию
onLayoutComplete.
Наиболее часто используемые события:
Срабатывает после завершения размещения элементов.
msnry.on('layoutComplete', function(items) {
console.log('Items positioned:', items);
});
Вызывается после удаления элементов из сетки.
msnry.on('removeComplete', function(items) {
console.log('Removed items:', items);
});
Срабатывает после появления элементов.
msnry.on('revealComplete', function(items) {
console.log('Items revealed:', items);
});
Срабатывает после скрытия элементов.
msnry.on('hideComplete', function(items) {
console.log('Items hidden:', items);
});
Для отмены подписки используется метод:
masonryInstance.off(eventName, listener)
Параметры:
eventName — имя событияlistener — функция, ранее переданная в
onВажно: для корректной отписки требуется та же самая функция, которая использовалась при подписке.
function onLayoutComplete(items) {
console.log('Layout completed');
}
msnry.on('layoutComplete', onLayoutComplete);
// отмена подписки
msnry.off('layoutComplete', onLayoutComplete);
После вызова off обработчик больше не будет
вызываться.
JavaScript сравнивает функции по ссылке. Если передать новую функцию, даже с тем же кодом, отписка не произойдёт.
Некорректный пример:
msnry.on('layoutComplete', function() {
console.log('Layout done');
});
msnry.off('layoutComplete', function() {
console.log('Layout done');
});
Функции различаются по ссылке, поэтому подписка остаётся активной.
Корректная реализация:
function handler() {
console.log('Layout done');
}
msnry.on('layoutComplete', handler);
msnry.off('layoutComplete', handler);
Иногда требуется выполнить обработчик только один раз. Это можно реализовать вручную.
function handleLayout(items) {
console.log('First layout complete');
msnry.off('layoutComplete', handleLayout);
}
msnry.on('layoutComplete', handleLayout);
После первого срабатывания обработчик удаляется.
При использовании Masonry в SPA-приложениях (React, Vue, Angular) особенно важно удалять подписки при уничтожении компонента.
Пример структуры:
function initGrid() {
var grid = document.querySelector('.grid');
var msnry = new Masonry(grid, {
itemSelector: '.grid-item'
});
function handleLayout() {
console.log('Layout completed');
}
msnry.on('layoutComplete', handleLayout);
return {
destroy: function() {
msnry.off('layoutComplete', handleLayout);
msnry.destroy();
}
};
}
Метод destroy:
Без отписки возможно накопление обработчиков при повторной инициализации.
Проблемный сценарий:
function init() {
var msnry = new Masonry('.grid');
msnry.on('layoutComplete', function() {
console.log('Layout done');
});
}
Если init() вызывается несколько раз:
Layout done
Layout done
Layout done
Layout done
Количество вызовов увеличивается из-за накопленных подписок.
Правильная архитектура включает хранение ссылки на обработчик.
Удобный подход — хранить обработчики в структуре.
var handlers = {
layout: function(items) {
console.log('Layout complete', items);
},
remove: function(items) {
console.log('Items removed', items);
}
};
msnry.on('layoutComplete', handlers.layout);
msnry.on('removeComplete', handlers.remove);
// позже
msnry.off('layoutComplete', handlers.layout);
msnry.off('removeComplete', handlers.remove);
Такой способ облегчает поддержку кода.
В приложениях с динамической сменой контейнеров необходимо отключать старые обработчики перед созданием нового экземпляра Masonry.
var msnry;
var layoutHandler;
function createGrid(container) {
if (msnry) {
msnry.off('layoutComplete', layoutHandler);
msnry.destroy();
}
msnry = new Masonry(container, {
itemSelector: '.grid-item'
});
layoutHandler = function(items) {
console.log('New layout');
};
msnry.on('layoutComplete', layoutHandler);
}
Это предотвращает привязку обработчиков к устаревшим экземплярам.
Если используется большое количество событий, отписка может быть организована централизованно.
var listeners = [];
function addListener(event, handler) {
listeners.push({ event, handler });
msnry.on(event, handler);
}
function removeAllListeners() {
listeners.forEach(function(item) {
msnry.off(item.event, item.handler);
});
listeners = [];
}
Использование:
addListener('layoutComplete', handleLayout);
addListener('removeComplete', handleRemove);
// очистка
removeAllListeners();
Полный цикл работы с событиями:
var grid = document.querySelector('.grid');
var msnry = new Masonry(grid, {
itemSelector: '.grid-item',
columnWidth: 200
});
function onLayout(items) {
console.log('Layout finished', items.length);
}
function onRemove(items) {
console.log('Removed', items.length);
}
msnry.on('layoutComplete', onLayout);
msnry.on('removeComplete', onRemove);
// позже
msnry.off('layoutComplete', onLayout);
msnry.off('removeComplete', onRemove);
msnry.on('layoutComplete', function() {
console.log('done');
});
Отписаться от такого обработчика невозможно.
function init() {
var handler = function() {
console.log('layout');
};
msnry.on('layoutComplete', handler);
}
Если переменная handler недоступна вне функции, отписка
невозможна.
msnry.on('layoutComplete', handler);
msnry.on('layoutComplete', handler);
Обработчик будет вызван дважды.
Эффективная работа с событиями Masonry включает несколько принципов:
1. Хранение ссылок на обработчики
const handlers = {};
2. Централизованная регистрация
function bindEvents() {
msnry.on('layoutComplete', handlers.layout);
}
3. Централизованная очистка
function unbindEvents() {
msnry.off('layoutComplete', handlers.layout);
}
4. Очистка перед уничтожением
unbindEvents();
msnry.destroy();
Если обработчик продолжает существовать после удаления DOM-элементов или уничтожения экземпляра Masonry, могут возникать:
Особенно это критично в:
Корректное управление подписками обеспечивает стабильность и предсказуемость поведения интерфейса при работе с Masonry.