Бесконечная прокрутка (infinite scroll) — это механизм динамической подгрузки данных при достижении определённой позиции на странице. В контексте библиотеки Waypoints ключевая идея заключается в отслеживании момента, когда пользователь прокручивает страницу до заданного элемента (триггера), после чего выполняется загрузка следующей порции контента.
Waypoints предоставляет удобный способ «поймать» этот момент без постоянного опроса положения скролла, используя событийную модель.
Подключение библиотеки возможно несколькими способами:
<script src="https://cdnjs.cloudflare.com/ajax/libs/waypoints/4.0.1/jquery.waypoints.min.js"></script>
npm install waypoints
import 'waypoints/lib/jquery.waypoints';
Для реализации бесконечной прокрутки чаще всего используется jQuery-версия, так как она включает дополнительные плагины, включая Infinite Scroll.
Минимальная структура страницы:
<div id="content">
<div class="item">Элемент 1</div>
<div class="item">Элемент 2</div>
<div class="item">Элемент 3</div>
</div>
<div id="loader">Загрузка...</div>
Ключевые элементы:
#content)#loader) —
используется как триггерОсновная логика строится вокруг waypoint:
var loading = false;
var page = 1;
var waypoint = new Waypoint({
element: document.getElementById('loader'),
handler: function(direction) {
if (direction === 'down' && !loading) {
loadMoreContent();
}
},
offset: '100%'
});
Функция подгрузки контента:
function loadMoreContent() {
loading = true;
page++;
fetch('/api/data?page=' + page)
.then(response => response.json())
.then(data => {
appendItems(data);
loading = false;
waypoint.refresh();
});
}
waypoint.refresh()function appendItems(items) {
const container = document.getElementById('content');
items.forEach(item => {
const div = document.createElement('div');
div.className = 'item';
div.textContent = item.text;
container.appendChild(div);
});
}
Waypoints не отслеживает автоматически изменения DOM, поэтому после добавления элементов обязательно обновление.
Waypoints предоставляет готовый плагин:
<script src="waypoints.min.js"></script>
<script src="infinite.min.js"></script>
var infinite = new Waypoint.Infinite({
element: document.getElementById('content'),
items: '.item',
more: '.next-link',
offset: 'bottom-in-view',
loadingClass: 'loading'
});
<a class="next-link" href="/page/2">Следующая</a>
При достижении конца контейнера:
Offset определяет, когда именно сработает загрузка:
offset: '100%' // когда элемент полностью виден
offset: 'bottom-in-view' // когда нижняя граница в зоне видимости
offset: 200 // за 200px до элемента
offset: 300offset: '100%'При бесконечной прокрутке важно учитывать:
if (page > 10) {
waypoint.destroy();
}
let timeout;
function loadMoreContent() {
clearTimeout(timeout);
timeout = setTimeout(() => {
// загрузка
}, 200);
}
Использование отложенной загрузки снижает нагрузку:
<img data-src="image.jpg" class="lazy">
fetch('/api/data?page=' + page)
.then(response => {
if (!response.ok) {
throw new Error('Ошибка загрузки');
}
return response.json();
})
.catch(error => {
console.error(error);
loading = false;
});
При динамическом изменении структуры страницы:
waypoint.destroy();
waypoint = new Waypoint({
element: document.getElementById('loader'),
handler: handlerFunction
});
Waypoints поддерживает кастомные контейнеры:
new Waypoint({
element: document.getElementById('loader'),
handler: function() {
loadMoreContent();
},
context: document.getElementById('scroll-container')
});
overflow: scrollwindowWaypoints не обновляет позиции автоматически.
Решается через флаг loading.
Может приводить к слишком ранней или поздней загрузке.
При удалении элемента триггера waypoint перестаёт работать.
if (page % 2 === 0) {
loadImages();
} else {
loadArticles();
}
При изменении фильтра:
page = 1;
document.getElementById('content').innerHTML = '';
waypoint.refresh();
#loader {
text-align: center;
padding: 20px;
display: none;
}
.loading #loader {
display: block;
}
if (data.length === 0) {
waypoint.destroy();
document.getElementById('loader').textContent = 'Больше данных нет';
}
| Подход | Преимущества | Недостатки |
|---|---|---|
| Waypoint вручную | гибкость | больше кода |
| Infinite плагин | быстрый старт | меньше контроля |
Полезные техники:
console.log(waypoint.triggerPoint);
console.log(window.scrollY);
Waypoint.enableAll();
Waypoint.disableAll();
В React/Vue требуется:
useEffect(() => {
const waypoint = new Waypoint({...});
return () => waypoint.destroy();
}, []);
function setLoading(state) {
loading = state;
document.body.classList.toggle('loading', state);
}