Inview

Модуль Inview библиотеки Waypoints предназначен для отслеживания момента появления или исчезновения элемента в области видимости (viewport). В отличие от базового механизма waypoint, который реагирует на пересечение одной фиксированной линии, Inview анализирует положение элемента целиком относительно окна браузера.

Ключевая идея: элемент может находиться в одном из четырёх состояний:

  • enter — элемент полностью или частично появился в области видимости
  • entered — элемент уже находится внутри viewport
  • exit — элемент начал покидать область видимости
  • exited — элемент полностью вышел за пределы viewport

Это позволяет более гибко реагировать на прокрутку страницы, особенно при создании анимаций и ленивой загрузки.


Подключение и базовая инициализация

<script src="jquery.js"></script>
<script src="jquery.waypoints.min.js"></script>
<script src="inview.min.js"></script>

Пример инициализации:

var inview = new Waypoint.Inview({
  element: document.getElementById('block'),
  enter: function(direction) {
    console.log('Вошёл в экран');
  },
  entered: function(direction) {
    console.log('Находится в экране');
  },
  exit: function(direction) {
    console.log('Начал выход');
  },
  exited: function(direction) {
    console.log('Полностью вышел');
  }
});

Обработчики событий

enter

Срабатывает в момент, когда любая часть элемента появляется в viewport.

enter: function(direction) {
  if (direction === 'down') {
    console.log('Прокрутка вниз');
  } else {
    console.log('Прокрутка вверх');
  }
}

Особенности:

  • вызывается один раз при входе
  • не зависит от полного попадания элемента в экран

entered

Срабатывает после enter, когда элемент уже стабильно находится в зоне видимости.

entered: function() {
  this.element.classList.add('visible');
}

Используется для:

  • запуска анимаций
  • активации контента

exit

Срабатывает, когда элемент начинает покидать viewport.

exit: function(direction) {
  console.log('Начало выхода');
}

exited

Срабатывает, когда элемент полностью выходит за границы viewport.

exited: function() {
  this.element.classList.remove('visible');
}

Направление прокрутки

Каждый обработчик получает параметр direction:

  • 'down' — прокрутка вниз
  • 'up' — прокрутка вверх

Пример:

enter: function(direction) {
  if (direction === 'down') {
    console.log('Элемент появился снизу');
  }
}

Контекст this

Внутри обработчиков доступен объект waypoint:

entered: function() {
  console.log(this.element); // DOM-элемент
}

Управление экземпляром

Уничтожение

inview.destroy();

Удаляет все обработчики и освобождает ресурсы.


Отключение и включение

inview.disable();
inview.enable();

Практические сценарии использования

1. Анимации при прокрутке

new Waypoint.Inview({
  element: document.querySelector('.fade-block'),
  enter: function() {
    this.element.classList.add('fade-in');
  }
});

CSS:

.fade-block {
  opacity: 0;
  transition: opacity 1s;
}

.fade-in {
  opacity: 1;
}

2. Ленивый рендеринг

new Waypoint.Inview({
  element: document.getElementById('chart'),
  enter: function() {
    renderChart();
    this.destroy(); // больше не нужен
  }
});

3. Подгрузка изображений

new Waypoint.Inview({
  element: img,
  enter: function() {
    img.src = img.dataset.src;
  }
});

4. Счётчики и метрики

new Waypoint.Inview({
  element: document.querySelector('.stats'),
  entered: function() {
    startCounter();
  },
  exited: function() {
    stopCounter();
  }
});

Отличие от Intersection Observer

Характеристика Waypoints Inview Intersection Observer
Поддержка старых браузеров высокая ограниченная
Простота API высокая средняя
Производительность ниже выше
Гибкость настройки средняя высокая

Ограничения

  • Использует события прокрутки, что может влиять на производительность при большом количестве элементов
  • Требует подключения jQuery (в большинстве сборок)
  • Не поддерживает тонкую настройку порогов пересечения (threshold), как в Intersection Observer

Оптимизация работы

Минимизация количества экземпляров

document.querySelectorAll('.item').forEach(function(el) {
  new Waypoint.Inview({ element: el });
});

Лучше группировать или ограничивать количество наблюдаемых элементов.


Удаление после использования

enter: function() {
  doSomething();
  this.destroy();
}

Использование debounce/throttle

При сложных сценариях стоит ограничивать частоту вызовов внутри обработчиков.


Расширенные приёмы

Комбинирование с обычными Waypoints

new Waypoint({
  element: el,
  handler: function() {
    console.log('Пересечение точки');
  },
  offset: '50%'
});

Используется вместе с Inview для более точного контроля.


Работа с классами состояния

new Waypoint.Inview({
  element: el,
  enter: function() {
    el.classList.add('inview');
  },
  exit: function() {
    el.classList.remove('inview');
  }
});

Повторные анимации

new Waypoint.Inview({
  element: el,
  enter: function() {
    el.classList.add('animate');
  },
  exited: function() {
    el.classList.remove('animate');
  }
});

Позволяет воспроизводить анимацию при каждом появлении элемента.


Взаимодействие с DOM

Inview не изменяет DOM напрямую, а только предоставляет события. Управление полностью остаётся за разработчиком:

  • добавление/удаление классов
  • изменение атрибутов
  • запуск JS-логики

Типичные ошибки

1. Повторная инициализация одного элемента

new Waypoint.Inview({ element: el });
new Waypoint.Inview({ element: el }); // ошибка

2. Отсутствие destroy

При динамических интерфейсах (SPA) это приводит к утечкам памяти.


3. Слишком тяжёлые обработчики

enter: function() {
  heavyFunction(); // может тормозить прокрутку
}

Архитектурные рекомендации

  • отделять логику отображения от логики наблюдения
  • использовать Inview как триггер, а не как место основной логики
  • применять CSS-анимации вместо JS, где возможно
  • избегать глубокой вложенности обработчиков

Сравнение состояний

Событие Когда происходит
enter элемент впервые появляется
entered элемент уже в зоне видимости
exit элемент начинает исчезать
exited элемент полностью исчез

Поведение при быстрой прокрутке

Если элемент быстро проскроллен:

  • enter и exit могут происходить почти одновременно
  • entered может не успеть сработать

Это важно учитывать при построении логики.


Поддержка контейнеров прокрутки

По умолчанию отслеживается окно браузера, но возможно указать контейнер:

new Waypoint.Inview({
  element: el,
  context: document.querySelector('.scroll-container')
});

Жизненный цикл Inview

  1. Инициализация
  2. Регистрация обработчиков
  3. Отслеживание прокрутки
  4. Генерация событий
  5. Уничтожение или отключение

Использование в SPA

При работе с React, Vue или Angular:

  • обязательно уничтожать waypoint при размонтировании компонента
  • создавать заново при повторном рендере

Производительность

При большом количестве элементов:

  • увеличивается нагрузка на scroll events

  • рекомендуется:

    • виртуализация списков
    • использование Intersection Observer как альтернативы
    • объединение логики

Гибкость применения

Inview подходит для:

  • анимаций при прокрутке
  • lazy loading
  • аналитики (отслеживание видимости блоков)
  • управления состоянием интерфейса
  • создания интерактивных лендингов

Внутренний механизм

Inview создаёт несколько waypoint-объектов:

  • верхняя граница элемента
  • нижняя граница элемента

Это позволяет точно определять вход и выход из viewport.


Итерация по элементам

var elements = document.querySelectorAll('.track');

elements.forEach(function(el) {
  new Waypoint.Inview({ element: el });
});

Совмещение с CSS transitions

Inview часто используется как триггер:

enter: function() {
  this.element.classList.add('active');
}

Анимация полностью реализуется в CSS.


Контроль повторного срабатывания

enter: function() {
  if (!this.triggered) {
    doSomething();
    this.triggered = true;
  }
}

Итоговая структура использования

  1. Выбор элемента
  2. Создание Inview
  3. Определение обработчиков
  4. Управление состоянием
  5. Очистка ресурсов