
Бесконечная прокрутка (Infinite Scroll) — это техника, которая загружает новый контент автоматически при прокрутке страницы до конца, позволяя пользователю просматривать информацию без необходимости переключения между страницами. Этот подход широко используется в социальных сетях, блогах и других контент-платформах для улучшения пользовательского опыта. В этом тренажере вы научитесь реализовывать бесконечную прокрутку с использованием JavaScript — от простой детекции прокрутки до оптимизированной асинхронной загрузки данных с сервера. Вы будете работать с событиями прокрутки, Intersection Observer API, обработкой состояния загрузки и другими техниками, необходимыми для создания плавной и эффективной бесконечной прокрутки.
- Модуль 1: Основы выбора элементов
- Выбор элемента по ID.
- Выбор элементов по классу.
- Выбор элементов по тегу.
- Выбор по селектору CSS.
- Выбор по атрибуту.
- Поиск элементов внутри другого элемента.
- Поиск родительского элемента.
- Поиск соседних элементов (предыдущий, следующий).
- Поиск первого и последнего дочернего элемента.
- Поиск всех дочерних элементов.
- Модуль 2: Манипуляция содержимым
- Модуль 3: Работа с атрибутами
- Модуль 4: Управление классами
- Модуль 5: Управление стилями
- Модуль 6: Создание и удаление элементов
- Создание нового элемента.
- Вставка элемента перед другим элементом.
- Вставка элемента после другого элемента.
- Добавление элемента в определенную позицию внутри списка дочерних элементов.
- Удаление элемента из DOM.
- Замена одного элемента другим.
- Перемещение существующего элемента в другое место DOM..
- Очистка содержимого элемента без его удаления.
- Модуль 7: Обработка событий
- Модуль 8: Работа с формами
- Модуль 9: Продвинутые манипуляции
- Модуль 10: Работа с размерами и прокруткой
- Получение размеров элемента.
- Получение позиции элемента относительно окна браузера.
- Получение позиции элемента относительно родительского элемента.
- Управление прокруткой страницы.
- Определение, виден ли элемент в текущей области просмотра.
- Плавная прокрутка к элементу.
- Создание элемента, который фиксируется при прокрутке.
- Модуль 11: Работа с медиа-элементами
- Модуль 12: Практические задания
Определение достижения конца страницы
В этом задании вам нужно реализовать функцию, которая определяет, когда пользователь прокрутил страницу до конца. Когда пользователь достигает конца страницы, в консоль должно выводиться сообщение 'Достигнут конец страницы'.
body {height: 200px;}
.content {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.placeholder {
background: linear-gradient(#f0f0f0, #d0d0d0);
}
<div class="content">
<h1>Определение конца страницы</h1>
<p>Прокрутите страницу вниз, чтобы увидеть, как работает скрипт.</p>
<div class="placeholder" style="height: 1500px;"></div>
<p>Конец страницы</p>
</div>
function checkScrollEnd() {
const scrollTop = input__1.scrollTop || document.body.scrollTop;
const scrollHeight = input__2.scrollHeight || document.body.scrollHeight;
const clientHeight = input__3.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 5) {
console.log('Достигнут конец страницы');
}
}
input__4.addEventListener('input__5', checkScrollEnd);
Добавление новых элементов при прокрутке
В этом задании нужно добавлять новые элементы в контейнер при достижении конца страницы. Когда пользователь прокручивает страницу до конца, должны добавляться 5 новых абзацев с текстом.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#content p {
padding: 15px;
background-color: #f5f5f5;
border-radius: 5px;
margin: 10px 0;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
<div class="container">
<h1>Динамическая загрузка контента</h1>
<p>Прокрутите вниз, чтобы загрузить больше элементов.</p>
<div id="content">
<p>Элемент 1</p>
<p>Элемент 2</p>
<p>Элемент 3</p>
<p>Элемент 4</p>
<p>Элемент 5</p>
</div>
</div>
let itemCount = 5;
function addItems() {
const contentDiv = document.getElementById('input__1');
for (let i = 0; i < 5; i++) {
const newItem = input__2.createElement('input__3');
itemCount++;
newItem.input__4 = `Элемент ${itemCount}`;
input__5.appendChild(newItem);
}
}
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10) {
addItems();
}
}
window.addEventListener('scroll', checkScrollEnd);
Индикатор загрузки при прокрутке
В этом задании нужно реализовать индикатор загрузки, который отображается при достижении конца страницы. После имитации загрузки (с помощью setTimeout) должны добавляться новые элементы, а индикатор должен скрываться.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.item {
padding: 20px;
background-color: #f0f0f0;
margin: 10px 0;
border-radius: 5px;
}
.loading-indicator {
text-align: center;
padding: 15px;
background-color: #ffeb3b;
margin: 10px 0;
border-radius: 5px;
display: none;
}
<div class="container">
<h1>Загрузка с индикатором</h1>
<div id="content">
<div class="item">Элемент 1</div>
<div class="item">Элемент 2</div>
<div class="item">Элемент 3</div>
<div class="item">Элемент 4</div>
<div class="item">Элемент 5</div>
</div>
<div id="loading" class="loading-indicator">Загрузка...</div>
</div>
let itemCount = 5;
let isLoading = false;
function addItems() {
const contentDiv = document.getElementById('content');
const loadingIndicator = document.getElementById('input__1');
if (isLoading) return;
isLoading = true;
loadingIndicator.style.input__2 = 'input__3';
// Имитация загрузки данных
input__4(function() {
for (let i = 0; i < 5; i++) {
const newItem = document.createElement('div');
newItem.className = 'item';
itemCount++;
newItem.textContent = `Элемент ${itemCount}`;
contentDiv.appendChild(newItem);
}
isLoading = false;
loadingIndicator.style.display = 'input__5';
}, 1500);
}
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10 && !isLoading) {
addItems();
}
}
window.addEventListener('scroll', checkScrollEnd);
Загрузка данных из массива
В этом задании нужно реализовать загрузку данных из предопределенного массива. При прокрутке страницы до конца должны загружаться следующие элементы из массива, пока они не закончатся. После загрузки всех данных должно появиться сообщение 'Больше нет данных'.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
#content div {
padding: 15px;
margin: 10px 0;
background-color: #f0f0f0;
border-radius: 5px;
}
.loading, .end-message {
text-align: center;
padding: 15px;
margin: 10px 0;
border-radius: 5px;
display: none;
}
.loading {
background-color: #ffeb3b;
}
.end-message {
background-color: #e0e0e0;
}
<div class="container">
<h1>Загрузка данных из массива</h1>
<div id="content"></div>
<div id="loading" class="loading">Загрузка...</div>
<div id="end-message" class="end-message">Больше нет данных</div>
</div>
// Данные для загрузки
const items = [
"Первый элемент", "Второй элемент", "Третий элемент", "Четвертый элемент", "Пятый элемент",
"Шестой элемент", "Седьмой элемент", "Восьмой элемент", "Девятый элемент", "Десятый элемент",
"Одиннадцатый элемент", "Двенадцатый элемент", "Тринадцатый элемент", "Четырнадцатый элемент", "Пятнадцатый элемент"
];
let currentIndex = 0;
let isLoading = false;
function loadMoreItems() {
if (isLoading) return;
const contentDiv = document.getElementById('input__1');
const loadingIndicator = document.getElementById('loading');
const endMessage = document.getElementById('input__2');
if (currentIndex >= items.input__3) {
endMessage.style.display = 'block';
return;
}
isLoading = true;
loadingIndicator.style.display = 'block';
setTimeout(function() {
// Количество элементов для загрузки за один раз
const itemsToLoad = Math.min(5, items.length - currentIndex);
for (let i = 0; i < itemsToLoad; i++) {
const newItem = document.createElement('div');
newItem.textContent = items[input__4];
contentDiv.input__5(newItem);
currentIndex++;
}
isLoading = false;
loadingIndicator.style.display = 'none';
if (currentIndex >= items.length) {
endMessage.style.display = 'block';
}
}, 1000);
}
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10 && !isLoading) {
loadMoreItems();
}
}
// Загружаем начальные элементы
loadMoreItems();
window.addEventListener('scroll', checkScrollEnd);
Асинхронная загрузка данных с сервера
Эта задача только для примера. В этом задании нужно реализовать асинхронную загрузку данных с использованием Fetch API. При прокрутке страницы до конца должен выполняться запрос к API, и полученные данные должны добавляться на страницу.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.post {
padding: 15px;
margin: 15px 0;
background-color: #f9f9f9;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.post h2 {
margin-top: 0;
color: #333;
}
.post p {
color: #666;
}
.loading-indicator, .error-message {
text-align: center;
padding: 15px;
margin: 15px 0;
border-radius: 5px;
display: none;
}
.loading-indicator {
background-color: #e3f2fd;
}
.error-message {
background-color: #ffebee;
color: #c62828;
}
<div class="container">
<h1>Асинхронная загрузка данных</h1>
<div id="posts"></div>
<div id="loading" class="loading-indicator">Загрузка данных...</div>
<div id="error" class="error-message">Ошибка загрузки данных</div>
</div>
let page = 1;
let isLoading = false;
async function loadPosts() {
if (isLoading) return;
const postsContainer = document.getElementById('posts');
const loadingIndicator = document.getElementById('loading');
const errorMessage = document.getElementById('error');
isLoading = true;
loadingIndicator.style.display = 'block';
errorMessage.style.display = 'none';
try {
const response = await input__1('https://naytikurs.ru/posts?_page=' + page + '&_limit=5');
if (!response.input__2) {
throw new Error('Ошибка загрузки данных');
}
const posts = await response.input__3();
if (posts.length === 0) {
// Больше нет данных
loadingIndicator.textContent = 'Больше нет данных';
return;
}
posts.forEach(post => {
const postElement = document.createElement('div');
postElement.className = 'input__4';
const title = document.createElement('h2');
title.textContent = post.title;
const body = document.createElement('p');
body.textContent = post.body;
postElement.appendChild(title);
postElement.appendChild(body);
postsContainer.input__5(postElement);
});
page++;
} catch (error) {
errorMessage.style.display = 'block';
console.error('Ошибка загрузки:', error);
} finally {
isLoading = false;
loadingIndicator.style.display = 'none';
}
}
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10 && !isLoading) {
loadPosts();
}
}
// Загружаем начальные посты
loadPosts();
window.addEventListener('scroll', checkScrollEnd);
Использование Intersection Observer для бесконечной прокрутки
В этом задании нужно реализовать бесконечную прокрутку с использованием Intersection Observer API вместо события прокрутки. Нужно создать наблюдатель, который будет отслеживать видимость специального элемента-сенсора в конце страницы.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.item {
padding: 20px;
margin: 10px 0;
background-color: #f0f0f0;
border-radius: 5px;
}
.loading-indicator {
text-align: center;
padding: 15px;
margin: 10px 0;
background-color: #e3f2fd;
border-radius: 5px;
display: none;
}
.sentinel {
height: 20px;
margin-bottom: 20px;
}
<div class="container">
<h1>Бесконечная прокрутка с Intersection Observer</h1>
<div id="content">
<div class="item">Элемент 1</div>
<div class="item">Элемент 2</div>
<div class="item">Элемент 3</div>
<div class="item">Элемент 4</div>
<div class="item">Элемент 5</div>
</div>
<div id="loading" class="loading-indicator">Загрузка...</div>
<div id="sentinel" class="sentinel"></div>
</div>
let itemCount = 5;
let isLoading = false;
function addItems() {
if (isLoading) return;
const contentDiv = document.getElementById('content');
const loadingIndicator = document.getElementById('loading');
isLoading = true;
loadingIndicator.style.display = 'block';
setTimeout(function() {
for (let i = 0; i < 5; i++) {
const newItem = document.createElement('div');
newItem.className = 'item';
itemCount++;
newItem.textContent = `Элемент ${itemCount}`;
contentDiv.appendChild(newItem);
}
isLoading = false;
loadingIndicator.style.display = 'none';
}, 1000);
}
// Создаем Intersection Observer
const options = {
root: input__1,
rootMargin: 'input__2',
threshold: input__3
};
const observer = new input__4(function(entries) {
entries.forEach(entry => {
if (entry.input__5 && !isLoading) {
addItems();
}
});
}, options);
// Начинаем наблюдение за сенсором
const sentinel = document.getElementById('sentinel');
observer.observe(sentinel);
Кнопка 'Загрузить еще' с бесконечной прокруткой
В этом задании нужно реализовать комбинированный подход: автоматическая загрузка при прокрутке и кнопка 'Загрузить еще'. Пользователь может либо прокрутить страницу до конца, либо нажать кнопку для загрузки дополнительных элементов.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 600px;
margin: 0 auto;
padding: 20px;
}
.item {
padding: 20px;
margin: 10px 0;
background-color: #f0f0f0;
border-radius: 5px;
}
.loading-indicator {
text-align: center;
padding: 15px;
margin: 10px 0;
background-color: #e3f2fd;
border-radius: 5px;
display: none;
}
.load-more-button {
display: block;
width: 100%;
padding: 15px;
background-color: #2196f3;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
margin: 20px 0;
transition: background-color 0.3s;
}
.load-more-button:hover {
background-color: #0b7dda;
}
<div class="container">
<h1>Комбинированная загрузка</h1>
<div id="content">
<div class="item">Элемент 1</div>
<div class="item">Элемент 2</div>
<div class="item">Элемент 3</div>
<div class="item">Элемент 4</div>
<div class="item">Элемент 5</div>
</div>
<div id="loading" class="loading-indicator">Загрузка...</div>
<button id="load-more" class="load-more-button">Загрузить еще</button>
</div>
let itemCount = 5;
let isLoading = false;
function loadMoreItems() {
if (isLoading) return;
const contentDiv = document.getElementById('content');
const loadingIndicator = document.getElementById('loading');
const loadMoreButton = document.getElementById('load-more');
isLoading = true;
loadingIndicator.style.display = 'block';
loadMoreButton.disabled = true;
setTimeout(function() {
for (let i = 0; i < 5; i++) {
const newItem = document.createElement('div');
newItem.className = 'item';
itemCount++;
newItem.textContent = `Элемент ${itemCount}`;
contentDiv.appendChild(newItem);
}
isLoading = false;
loadingIndicator.style.display = 'none';
loadMoreButton.disabled = false;
}, 1000);
}
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10 && !isLoading) {
loadMoreItems();
}
}
// Добавляем обработчик события для кнопки
const loadMoreButton = document.getElementById('input__1');
loadMoreButton.addEventListener('input__2', input__3);
// Добавляем обработчик события для прокрутки
input__4.addEventListener('input__5', checkScrollEnd);
Загрузка изображений с ленивой загрузкой
В этом задании нужно реализовать бесконечную прокрутку с ленивой загрузкой изображений. При прокрутке страницы должны загружаться новые изображения, но они должны загружаться только тогда, когда становятся видимыми в области просмотра.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
#gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
gap: 15px;
}
.image-container {
border-radius: 5px;
overflow: hidden;
box-shadow: 0 2px 5px rgba(0,0,0,0.1);
}
.lazy-image {
width: 100%;
height: 200px;
object-fit: cover;
transition: opacity 0.3s;
opacity: 0;
}
.lazy-image.loaded {
opacity: 1;
}
.loading-indicator {
text-align: center;
padding: 15px;
margin: 20px 0;
background-color: #e3f2fd;
border-radius: 5px;
display: none;
}
.sentinel {
height: 20px;
margin-bottom: 20px;
}
<div class="container">
<h1>Галерея с ленивой загрузкой</h1>
<div id="gallery"></div>
<div id="loading" class="loading-indicator">Загрузка изображений...</div>
<div id="sentinel" class="sentinel"></div>
</div>
// Массив URL изображений
const imageUrls = [
"https://naytikurs.ru/assets/uploads/2025/03/3d-modelirovanie-i-vizualizatsiya-test-dlya-spetsialistov-v-trehmernoj-grafike2-300x300.png",
"https://naytikurs.ru/assets/uploads/2025/03/3d-modelirovanie-i-vizualizatsiya-test-dlya-spetsialistov-v-trehmernoj-grafike-300x300.png",
"https://naytikurs.ru/assets/uploads/2025/03/3d-modelirovanie-i-vizualizatsiya-test-dlya-spetsialistov-v-trehmernoj-grafike3-300x300.png",
"https://naytikurs.ru/assets/uploads/2025/03/3d-modelirovanie-i-vizualizatsiya-test-dlya-spetsialistov-v-trehmernoj-grafike4-300x300.png",
"https://naytikurs.ru/assets/uploads/2025/03/naskolko-vas-legko-obmanut-v-internete-300x300.png",
"https://naytikurs.ru/assets/uploads/2025/03/test-na-znanie-osnov-kiberbezopasnosti-300x300.png"
];
let currentIndex = 0;
let isLoading = false;
// Функция для создания элемента изображения
function createImageElement(url) {
const container = document.createElement('div');
container.className = 'image-container';
const img = document.createElement('img');
img.className = 'lazy-image';
img.input__1 = 'data-src'; // Используем data-атрибут для хранения URL
img.setAttribute('input__2', url);
container.appendChild(img);
return container;
}
// Функция для загрузки изображений
function loadMoreImages() {
if (isLoading) return;
const gallery = document.getElementById('gallery');
const loadingIndicator = document.getElementById('loading');
isLoading = true;
loadingIndicator.style.display = 'block';
setTimeout(function() {
for (let i = 0; i < 6; i++) {
// Используем циклический доступ к массиву изображений
const imageIndex = currentIndex % imageUrls.length;
const imageUrl = imageUrls[imageIndex];
const imageElement = createImageElement(imageUrl);
gallery.appendChild(imageElement);
currentIndex++;
}
isLoading = false;
loadingIndicator.style.display = 'none';
// Обновляем наблюдатель для новых изображений
setupLazyLoading();
}, 1000);
}
// Настройка ленивой загрузки
function setupLazyLoading() {
const lazyImages = document.querySelectorAll('img.lazy-image:not(.loaded)');
const imageObserver = new IntersectionObserver(function(entries, observer) {
entries.forEach(entry => {
if (entry.input__3) {
const img = entry.target;
const src = img.getAttribute('data-src');
img.input__4 = src;
img.classList.add('input__5');
// Прекращаем наблюдение после загрузки
observer.unobserve(img);
}
});
}, { rootMargin: '0px 0px 100px 0px' });
lazyImages.forEach(img => {
imageObserver.observe(img);
});
}
// Настройка бесконечной прокрутки
const scrollObserver = new IntersectionObserver(function(entries) {
entries.forEach(entry => {
if (entry.isIntersecting && !isLoading) {
loadMoreImages();
}
});
}, { rootMargin: '0px 0px 200px 0px' });
// Начинаем наблюдение за сенсором прокрутки
const sentinel = document.getElementById('sentinel');
scrollObserver.observe(sentinel);
// Загружаем начальные изображения
loadMoreImages();
Бесконечная прокрутка с управлением состоянием загрузки
В этом задании нужно реализовать бесконечную прокрутку с полным управлением состоянием загрузки. Нужно обрабатывать начальную загрузку, дополнительные загрузки при прокрутке, состояния загрузки, ошибки и отсутствие данных.
body {height: 200px;}
.container {
font-family: Arial, sans-serif;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.item {
padding: 20px;
margin: 10px 0;
background-color: #f9f9f9;
border-radius: 5px;
box-shadow: 0 1px 3px rgba(0,0,0,0.1);
}
.status-indicator {
padding: 15px;
margin: 15px 0;
border-radius: 5px;
text-align: center;
display: none;
}
.loading {
background-color: #e3f2fd;
}
.error {
background-color: #ffebee;
color: #c62828;
}
.no-more {
background-color: #f5f5f5;
color: #616161;
}
#retry {
margin-left: 10px;
padding: 5px 10px;
background-color: #f44336;
color: white;
border: none;
border-radius: 3px;
cursor: pointer;
}
<div class="container">
<h1>Бесконечная прокрутка с управлением состоянием</h1>
<div id="content"></div>
<div id="loading" class="status-indicator loading">Загрузка данных...</div>
<div id="error" class="status-indicator error">Ошибка загрузки данных. <button id="retry">Повторить</button></div>
<div id="no-more" class="status-indicator no-more">Больше нет данных</div>
</div>
let page = 1;
let isLoading = false;
let hasError = false;
let hasMore = true;
async function loadData() {
if (isLoading || !hasMore) return;
const contentDiv = document.getElementById('content');
const loadingIndicator = document.getElementById('loading');
const errorIndicator = document.getElementById('error');
const noMoreIndicator = document.getElementById('no-more');
// Обновляем состояние и UI
isLoading = true;
hasError = false;
updateStatusIndicators();
try {
// Имитируем загрузку данных с сервера
const data = await fetchData(page);
if (data.length === 0) {
// Больше нет данных
hasMore = input__1;
updateStatusIndicators();
return;
}
// Добавляем элементы на страницу
data.forEach(item => {
const itemElement = document.createElement('div');
itemElement.className = 'item';
itemElement.textContent = item.text;
contentDiv.appendChild(itemElement);
});
// Увеличиваем номер страницы
input__2++;
} catch (error) {
// Обрабатываем ошибку
hasError = input__3;
console.error('Ошибка загрузки данных:', error);
} finally {
// Обновляем состояние и UI
isLoading = false;
updateStatusIndicators();
}
}
// Функция для обновления индикаторов состояния
function updateStatusIndicators() {
const loadingIndicator = document.getElementById('loading');
const errorIndicator = document.getElementById('error');
const noMoreIndicator = document.getElementById('no-more');
loadingIndicator.style.display = isLoading ? 'input__4' : 'none';
errorIndicator.style.display = hasError ? 'block' : 'none';
noMoreIndicator.style.display = !hasMore && !isLoading && !hasError ? 'block' : 'none';
}
// Функция для имитации загрузки данных с сервера
async function fetchData(page) {
return new Promise((resolve, reject) => {
setTimeout(() => {
// Имитируем ошибку для страницы 3
if (page === 3 && Math.random() < 0.5) {
reject(new Error('Ошибка сети'));
return;
}
// Имитируем отсутствие данных после страницы 5
if (page > 5) {
resolve([]);
return;
}
// Генерируем тестовые данные
const items = [];
for (let i = 1; i <= 5; i++) {
items.push({
id: (page - 1) * 5 + i,
text: `Элемент ${(page - 1) * 5 + i} (страница ${page})`
});
}
resolve(items);
}, 1000);
});
}
// Обработчик события прокрутки
function checkScrollEnd() {
const scrollTop = document.documentElement.scrollTop || document.body.scrollTop;
const scrollHeight = document.documentElement.scrollHeight || document.body.scrollHeight;
const clientHeight = document.documentElement.clientHeight || document.body.clientHeight;
if (scrollTop + clientHeight >= scrollHeight - 10 && !isLoading && hasMore && !hasError) {
input__5();
}
}
// Добавляем обработчик для кнопки повторной попытки
document.getElementById('retry').addEventListener('click', function() {
if (hasError) {
hasError = false;
updateStatusIndicators();
loadData();
}
});
// Добавляем обработчик события для прокрутки
window.addEventListener('scroll', checkScrollEnd);
// Загружаем начальные данные
loadData();