Комбинирование нескольких коллбэков

Headroom.js предоставляет механизм для управления видимостью верхнего меню или шапки страницы при скролле. Одной из ключевых возможностей является использование коллбэков, которые срабатывают при определённых событиях: onPin, onUnpin, onTop, onNotTop, onBottom, onNotBottom. Правильное комбинирование нескольких коллбэков позволяет реализовать сложное поведение интерфейса без конфликтов и дублирования кода.


Регистрация нескольких функций на одно событие

Headroom.js принимает объект с коллбэками при инициализации:

const header = document.querySelector('header');
const headroom = new Headroom(header, {
  onPin: () => console.log('Pinned'),
  onUnpin: () => console.log('Unpinned')
});
headroom.init();

Если требуется вызвать несколько функций при одном событии, нельзя напрямую присвоить массив к ключу, как в обычных объектах JavaScript. Решение — обёртка, которая последовательно вызывает все необходимые функции:

function combineCallbacks(...fns) {
  return function(...args) {
    fns.forEach(fn => {
      if (typeof fn === 'function') fn(...args);
    });
  };
}

const headroom = new Headroom(header, {
  onPin: combineCallbacks(
    () => console.log('Pinned'),
    () => header.classList.add('highlight')
  ),
  onUnpin: combineCallbacks(
    () => console.log('Unpinned'),
    () => header.classList.remove('highlight')
  )
});
headroom.init();

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


Контроль порядка выполнения

Порядок вызова функций имеет значение, особенно если одна из функций зависит от изменений, внесённых другой. Например, добавление и удаление классов должно происходить в правильной последовательности:

onPin: combineCallbacks(
  () => header.classList.remove('hidden'),
  () => header.classList.add('active'),
  () => console.log('Header pinned and classes updated')
)

Функции выполняются строго в порядке передачи. Любая ошибка внутри одной из функций не прерывает остальные, если использовать защищённый вызов:

function safeCall(fn) {
  try {
    fn();
  } catch (e) {
    console.error('Ошибка в коллбэке:', e);
  }
}

function combineCallbacksSafe(...fns) {
  return function(...args) {
    fns.forEach(fn => safeCall(() => fn(...args)));
  };
}

Это особенно важно при работе с внешними библиотеками или динамическим контентом.


Комбинирование коллбэков разных типов

Headroom.js поддерживает несколько событий, и часто возникает необходимость синхронно обрабатывать изменения скролла и состояния шапки:

const headroom = new Headroom(header, {
  onPin: combineCallbacks(
    () => header.classList.add('pinned'),
    () => toggleShadow(false)
  ),
  onUnpin: combineCallbacks(
    () => header.classList.remove('pinned'),
    () => toggleShadow(true)
  ),
  onTop: () => header.classList.add('at-top'),
  onNotTop: () => header.classList.remove('at-top')
});
  • onPin и onUnpin управляют видимостью и эффектами при прокрутке вниз/вверх.
  • onTop и onNotTop позволяют добавить визуальную подсказку о начале страницы.

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


Использование замыканий для передачи состояния

При сложной логике полезно хранить промежуточное состояние через замыкания:

const state = { count: 0 };

const headroom = new Headroom(header, {
  onPin: combineCallbacks(
    () => state.count++,
    () => console.log(`Pinned ${state.count} times`)
  )
});

Замыкание сохраняет значение count между вызовами, что позволяет отслеживать количество событий или динамически изменять поведение коллбэков.


Практический пример: шапка с динамическими классами и анимациями

function addAnimation(className) {
  header.classList.add(className);
  setTimeout(() => header.classList.remove(className), 300);
}

const headroom = new Headroom(header, {
  onPin: combineCallbacks(
    () => header.classList.remove('hidden'),
    () => addAnimation('slide-down')
  ),
  onUnpin: combineCallbacks(
    () => header.classList.add('hidden'),
    () => addAnimation('slide-up')
  ),
  onTop: () => header.classList.add('top-highlight'),
  onNotTop: () => header.classList.remove('top-highlight')
});
headroom.init();

В этом сценарии:

  • Анимации добавляются при каждом событии без конфликтов.
  • Состояние шапки (hidden, top-highlight) обновляется независимо от анимаций.
  • Несколько коллбэков выполняются последовательно и безопасно, даже если одна из функций вызовет исключение.

Итоговые рекомендации

  1. Использовать обёртку combineCallbacks для нескольких функций на одно событие.
  2. Контролировать порядок выполнения, чтобы избежать конфликтов с классами или DOM-манипуляциями.
  3. Применять защиту через try/catch внутри коллбэков при сложной логике.
  4. Разделять логику разных событий (onPin, onTop, onBottom) для независимого управления визуальными эффектами.
  5. Использовать замыкания для сохранения состояния между вызовами коллбэков.

Эти подходы позволяют создавать гибкие и масштабируемые интерфейсы с Headroom.js, где множество действий при скролле выполняются безопасно и предсказуемо.