Бесконечный скроллинг на PHP: подгрузка записей через fetch

Короткий ответ: бесконечный скроллинг делается на связке JavaScript и PHP. JavaScript замечает, что пользователь дошел почти до конца страницы, отправляет запрос на PHP-файл, а PHP возвращает следующую порцию записей в JSON

PHP сам по себе не “слушает скролл” в браузере. Скролл происходит на клиенте, в JavaScript. PHP работает на сервере: получает запрос, берет данные из массива или базы и возвращает ответ

Структура проекта

Создадим три файла

infinite-scroll/
  index.php
  api.php
  data.php

В реальном проекте данные обычно берутся из базы. Для учебного примера начнем с массива, чтобы не отвлекаться на SQL

Файл с данными

data.php

<?php

$posts = [];

for ($i = 1; $i <= 100; $i++) {
    $posts[] = [
        'id' => $i,
        'title' => 'Запись ' . $i,
        'text' => 'Короткое описание записи номер ' . $i,
    ];
}

return $posts;

Так мы имитируем 100 записей

PHP endpoint для подгрузки

api.php

<?php

header('Content-Type: application/json; charset=utf-8');

$posts = require __DIR__ . '/data.php';

$limit = 10;
$offset = isset($_GET['offset']) ? (int) $_GET['offset'] : 0;

if ($offset < 0) {
    $offset = 0;
}

$chunk = array_slice($posts, $offset, $limit);

echo json_encode([
    'items' => $chunk,
    'nextOffset' => $offset + count($chunk),
    'hasMore' => $offset + count($chunk) < count($posts),
], JSON_UNESCAPED_UNICODE);

Этот файл возвращает не HTML, а JSON. Параметр offset говорит, сколько записей уже загружено

Страница со скроллингом

index.php

<!doctype html>
<html lang="ru">
<head>
    <meta charset="utf-8">
    <title>Бесконечный скроллинг на PHP</title>
    <style>
        body { font-family: Arial, sans-serif; max-width: 720px; margin: 40px auto; }
        .post { border-bottom: 1px solid #ddd; padding: 20px 0; }
        .loader { padding: 24px; text-align: center; color: #666; }
    </style>
</head>
<body>
    <h1>Бесконечный скроллинг на PHP</h1>
    <div id="posts"></div>
    <div id="loader" class="loader">Загрузка</div>

    <script>
        const postsElement = document.getElementById('posts');
        const loaderElement = document.getElementById('loader');

        let offset = 0;
        let loading = false;
        let hasMore = true;

        function renderPost(post) {
            const element = document.createElement('article');
            element.className = 'post';
            element.innerHTML = `
                <h2>${post.title}</h2>
                <p>${post.text}</p>
            `;
            postsElement.appendChild(element);
        }

        async function loadPosts() {
            if (loading || !hasMore) {
                return;
            }

            loading = true;
            loaderElement.textContent = 'Загрузка';

            const response = await fetch(`api.php?offset=${offset}`);
            const data = await response.json();

            data.items.forEach(renderPost);

            offset = data.nextOffset;
            hasMore = data.hasMore;
            loading = false;
            loaderElement.textContent = hasMore ? 'Прокрутите ниже' : 'Записей больше нет';
        }

        window.addEventListener('scroll', () => {
            const nearBottom = window.innerHeight + window.scrollY >= document.body.offsetHeight - 300;

            if (nearBottom) {
                loadPosts();
            }
        });

        loadPosts();
    </script>
</body>
</html>

Откройте страницу через локальный сервер. Сначала загрузятся первые записи, затем при прокрутке будут подгружаться следующие

Как запустить

В папке проекта выполните

php -S localhost:8000

Откройте

http://localhost:8000

Прокрутите страницу вниз. Если новые записи появляются без перезагрузки, бесконечный скроллинг работает

Как заменить массив на базу данных

В реальном проекте api.php обычно делает SQL-запрос с LIMIT и OFFSET

select id, title, text
from posts
order by id desc
limit 10 offset 20

В PHP значения limit и offset нужно приводить к числу, как в примере выше. Нельзя подставлять пользовательский ввод в SQL как строку без проверки

Почему нужен флаг loading

Без loading браузер может отправить несколько запросов подряд, пока пользователь находится у нижней части страницы. Тогда записи могут продублироваться или прийти не в том порядке

Флаг hasMore нужен, чтобы остановить запросы, когда сервер сказал: записей больше нет

Мини-практика

Измените limit с 10 на 5 и проверьте, как чаще начнутся подгрузки. Затем добавьте кнопку Загрузить еще и вызывайте loadPosts() по клику. Это хороший запасной вариант для пользователей, у которых автоматическая прокрутка работает неудобно

Частые ошибки

Пытаются сделать скролл только на PHP PHP работает на сервере. Событие прокрутки ловит JavaScript в браузере

Не защищают offset Приводите offset к числу и не доверяйте данным из $_GET

Отправляют много запросов подряд Используйте флаг loading, чтобы не запускать новую подгрузку до завершения старой

Не показывают конец списка Пользователь должен понимать, что записей больше нет

Что почитать дальше по PHP

Если нужен общий маршрут по теме, откройте рубрику PHP. Для соседних задач пригодятся эти разборы:

Оцените статью
0 0 голоса
Рейтинг статьи
Подписаться
Уведомить о
guest

0 комментариев
Старые
Новые Популярные
Межтекстовые Отзывы
Посмотреть все комментарии
0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x