Если вы используете какое-либо веб- или мобильное приложение, вы, возможно, сталкивались с таблицей данных, которая позволяет просматривать данные, разбивая их на несколько страниц. В мире разработки программного обеспечения это известно как пагинация.
Пагинация – это техника оптимизации, которая используется как на фронтенде, так и на бэкенде для повышения производительности ваших приложений. С помощью пагинации вы можете перейти к нужной странице и просмотреть результаты для этой конкретной страницы без загрузки дополнительных данных. В этом руководстве вы узнаете, как работать с Strapi для бэкенда и реализовать элементы управления пагинацией UI, создав фронтенд в Svelte.
Strapi – это безголовая CMS (система управления контентом) для Node.js для создания и разработки API. Она бесплатна и имеет открытый исходный код, и позволяет вам настраивать ее поведение в соответствии с вашими потребностями.
Для создания фронтенда вы будете использовать SvelteKit, который представляет собой фреймворк для создания веб-приложений любого размера. Он предоставляет вам лучшие возможности фронтенда и бэкенда в одностраничном приложении.
Весь исходный код этого руководства доступен в этом репозитории GitHub.
- Что такое пагинация?
- Типы пагинации
- Пагинация на основе смещения
- Пагинация на основе курсора
- Предварительные условия
- Настройка проекта
- Установка Strapi v4
- Создание типа коллекции статей
- Наполнение страпинга статьями
- Настройка разрешений для Strapi Article API
- Настройка Svelte
- Установка пакетов NPM
- Получение статей из Strapi
- Реализация элементов управления пагинацией в Svelte
- Тестирование пагинации
- Заключение
Что такое пагинация?
Как упоминалось выше, пагинация – это техника оптимизации, которая используется для повышения производительности ваших приложений. Например, если у вас есть огромный блог, содержащий более десяти тысяч статей, у вас есть API, который предоставляет эти данные вашему фронтенд-приложению.
Если вы попытаетесь получить и отправить все статьи сразу, вы можете столкнуться с проблемами пропускной способности, задержками, медленным временем отклика сервера и проблемами, связанными с памятью. Даже если вам удастся отправить все статьи, вы можете столкнуться с проблемами во внешнем приложении, такими как замирание браузера при медленном отклике, так как вам приходится отображать десятки тысяч записей во внешнем приложении. Короче говоря, ваш браузер может не реагировать на запросы.
Все эти проблемы могут привести к разочарованию пользователей и потере доходов.
Лучший способ преодолеть эти проблемы – получать статьи в небольших количествах. Например, вы можете получить первые пятьдесят статей, а затем, когда пользователь дойдет до конца списка, вы можете получить следующие пятьдесят статей и так далее. Это позволяет поддерживать производительность сервера и клиента и обеспечивает положительный пользовательский опыт. Весь этот процесс и есть пагинация.
Типы пагинации
Как правило, существует два способа реализации пагинации:
Пагинация на основе смещения
При пагинации на основе смещения следующие два входа используются для нарезки данных из базы данных:
- Start используется для указания индекса, из которого извлекаются записи.
- Limit используется для указания количества записей для выборки.
Пагинация на основе курсора
При пагинации на основе курсора для нарезки данных из базы данных используются входы limit и cursor:
- Limit используется для указания количества записей на каждой странице.
- Курсор используется для указания количества записей, которые нужно пропустить перед выборкой записей, и используется в сочетании с входом limit.
Предварительные условия
Чтобы следовать этому руководству, вам потребуется установить следующее:
- Node.js: в данном руководстве используется Node v14.19.0.
- Strapi: в данном руководстве используется Strapi v4.1.0.
- SvelteKit: в данном руководстве используется
next
версия SvelteKit.
Настройка проекта
Для настройки проекта вам понадобится основной каталог, в котором будет храниться код для фронтенда (Svelte) и бэкенда (Strapi). Для начала откройте терминал, перейдите по выбранному пути и создайте каталог проекта, выполнив следующую команду:
mkdir strapi-svelte-pagination
В директории strapi-svelte-pagination
вы установите проекты Strapi и Svelte.
Установка Strapi v4
В терминале выполните следующую команду для создания проекта Strapi:
npx create-strapi-app@latest backend --quickstart
Эта команда создаст проект Strapi с настройками быстрого запуска в каталоге backend
.
После завершения выполнения этой команды ваш проект Strapi запустится на порту 1337 и откроет localhost:1337/admin/auth/register-admin в вашем браузере. На этом этапе настройте своего административного пользователя:
Введите свои данные и нажмите кнопку Let’s start, после чего вы попадете в панель Strapi Dashboard:
Создание типа коллекции статей
Под заголовком Plugins в левой боковой панели перейдите на вкладку Content-Type Builder, а затем нажмите Create new collection type, чтобы создать новую коллекцию Strapi.
В появившемся модале создайте новый тип коллекции с “Article” в качестве Display Name; затем нажмите Continue:
Далее создайте два поля для вашего типа коллекции:
- Добавьте новое текстовое поле под названием “title” и выберите тип текста Short.
- Создайте новое текстовое поле под названием “description” и выберите тип текста Long.
После добавления всех полей нажмите кнопку Finish и выберите Save. Теперь у вас должны отображаться поля названия и описания:
На данном этапе тип коллекции настроен, и следующее, что вам нужно сделать, это добавить в него некоторые данные.
Наполнение страпинга статьями
Чтобы эффективно протестировать пагинацию, вам нужно добавить много записей. Ручное добавление этих записей может занять много времени, поэтому вы можете написать короткий скрипт для создания коллекции типа Article.
Для начала необходимо выключить сервер разработки Strapi и установить Faker, который позволяет генерировать огромное количество фальшивых (но реалистичных) данных для тестирования и разработки. Для этого выполните следующую команду в терминале:
npm install --save-dev @faker-js/faker
Затем создайте каталог utils
в каталоге src
. Затем в каталоге utils
создайте файл seed.js
и добавьте в него следующий код:
const { faker } = require("@faker-js/faker");
// 1
async function seedArticlesCollection() {
const numberOfRecordsToCreate = 207;
// 2
for (let i = 0; i < numberOfRecordsToCreate; i++) {
// 3
await strapi.api.article.services.article.create({
data: {
title: faker.lorem.words(),
description: faker.lorem.sentence(),
},
});
}
console.log(`Added ${numberOfRecordsToCreate} records`);
}
module.exports = { seedArticlesCollection };
В приведенном выше коде вы определяете функцию (seedArticlesCollection
) для посева типа коллекции статей. Вы также запускаете цикл for
для создания numberOfRecordsToCreate
количества записей. Затем вы используете службу Strapi для создания новой статьи и генерируете заголовок (faker.lorem.words()
) и описание (faker.lorem.sentence()
) с помощью Faker.
Далее откройте src/index.js
и добавьте в него следующий код:
"use strict";
// 1
const { seedArticlesCollection } = require("./utils/seed");
module.exports = {
...
// 2
async bootstrap() {
await seedArticlesCollection();
},
};
Здесь вы импортируете функцию seedArticlesCollection
и вызываете функцию seedArticlesCollection
в методе bootstrap
, который выполняется перед запуском вашего приложения Strapi.
Наконец, запустите сервер разработки Strapi, выполнив следующую команду:
npm run develop
После запуска сервера проверьте консоль на наличие следующего сообщения:
Далее проверьте тип коллекции Article, и вы должны увидеть там созданные записи:
Теперь вы можете удалить вызов функции seedArticlesCollection
в методе bootstrap
, иначе при каждом перезапуске сервера Strapi будут создаваться новые записи.
Настройка разрешений для Strapi Article API
Теперь, когда вы успешно посеяли Strapi, необходимо настроить разрешения для доступа к Strapi API. На данный момент у вас достаточно данных в вашей Strapi CMS, чтобы протестировать API.
Для начала откройте Postman и отправьте GET-запрос на конечную точку Article API: localhost:1337/api/articles. Вы не сможете получить доступ к конечной точке, пока не разрешите публичный доступ к ней.
Чтобы настроить разрешения для конечных точек API вашего типа содержимого Article, перейдите на вкладку Settings под заголовком General, а затем выберите Roles в разделе Users & Permissions Plugin. Поскольку вы хотите разрешить публичный доступ к вашим статьям, вам необходимо настроить разрешения, связанные с ролью Public. Нажмите на значок пера Edit справа от роли Public:
Прокрутите вниз, чтобы найти вкладку Разрешения и отметьте маршруты find и findOne для типа коллекции Article. После этого нажмите на кнопку Сохранить, чтобы сохранить обновленные разрешения:
Вернитесь в Postman и отправьте GET-запрос на localhost:1337/api/articles, и вы получите список статей из Strapi:
Прокрутив окно ответа вниз, вы найдете некоторые метаданные, связанные с пагинацией:
Затем отправьте еще один запрос к конечной точке articles
с параметром запроса pagination[page]
, чтобы получить список статей на странице 2:
Затем отправьте еще один запрос к конечной точке articles
с параметрами запроса pagination[page]
и pagination[pageSize]
, чтобы получить список статей на странице 2 и всего пятьдесят статей соответственно:
Вот и все. Ваш проект Strapi готов, и вы можете подключить его к любому фронтенд-приложению.
Настройка Svelte
В этом разделе вы создадите фронтенд-приложение Svelte и подключите его к бэкенду Strapi.
Поскольку ваше текущее окно терминала обслуживает проект Strapi, откройте другое окно терминала и выполните следующую команду для создания проекта Svelte:
npm init svelte@next frontend
В терминале вам будет задано несколько вопросов о вашем проекте Svelte. Для этого руководства выберите варианты, выделенные ниже:
После того, как вы ответите на все вопросы, Svelte CLI установит некоторые начальные зависимости. После завершения процесса установки перейдите в каталог frontend
и установите все оставшиеся зависимости, выполнив следующие команды:
cd frontend
npm install
Когда установка будет завершена, выполните следующую команду для запуска сервера разработки Svelte:
npm run dev -- --open
Это запустит сервер разработки на порту 3000 и приведет вас на localhost:3000. Ваш первый вид веб-сайта Svelte будет выглядеть следующим образом:
Установка пакетов NPM
Для вашего приложения Svelte вам понадобятся следующие два пакета NPM:
- axios: позволяет работать с HTTP-запросами.
- qs: позволяет разбирать и строчить строки запросов с некоторыми дополнительными мерами безопасности.
Начните с выключения сервера разработки Svelte, нажав Control-C в терминале; затем выполните следующую команду для установки вышеуказанных пакетов NPM:
npm install axios qs
Теперь вы готовы написать код в вашем приложении Svelte для получения статей.
Получение статей из Strapi
После того как вы установили необходимые пакеты для разработки сайта Svelte, вам нужно создать страницу Статьи. На этой странице вы будете получать статьи из Strapi CMS и отображать их в пользовательском интерфейсе.
Для начала в директории src/routes
откройте index.svelte
и замените существующий код на следующий:
<script>
// 1
import { onMount } from 'svelte';
import axios from 'axios';
import * as qs from 'qs';
// 2
let stateLoading = true;
let stateArticles = null;
let stateMeta = null;
let stateCurrentPageNumber = 1;
let stateCurrentPageSize = 20;
// 3
async function getArticles(pageNumber, pageSize) {
const query = qs.stringify(
{
pagination: {
page: pageNumber,
pageSize: pageSize
}
},
{
encodeValuesOnly: true
}
);
const res = await axios.get(`http://localhost:1337/api/articles?${query}`);
return {
articles: res.data.data,
meta: res.data.meta
};
}
// 4
async function updateArticlesByPage(pageNumber) {
stateLoading = true;
stateCurrentPageNumber = pageNumber;
const { articles, meta } = await getArticles(stateCurrentPageNumber, stateCurrentPageSize);
stateArticles = articles;
stateMeta = meta;
stateLoading = false;
}
// 5
onMount(async () => {
await updateArticlesByPage(stateCurrentPageNumber);
});
</script>
<!-- 6 -->
<section>
<div class="container">
{#if stateLoading}
<p>Loading...</p>
{:else}
<div>
<h1>Strapi Articles ({stateMeta.pagination.total})</h1>
<div class="mb-4">
<!-- 7 -->
{#each stateArticles as article}
<div class="mb-4">
<h2 class="h4">{article.id} - {article.attributes.title}</h2>
<p class="mb-1">{article.attributes.description}</p>
</div>
{/each}
</div>
</div>
{/if}
</div>
</section>
В приведенном выше коде вы импортируете необходимые пакеты NPM и определяете переменные состояния.
Вы также определяете функцию getArticles
, которой передаете параметры page
и pageSize
. Затем вы преобразуете эти параметры в строку с помощью метода stringify
из qs
. Далее выполняется GET-запрос к конечной точке /api/articles
на localhost:1337 и возвращается объект, содержащий список articles
и детали пагинации в meta
.
После этого вы определяете функцию updateArticlesByPage
, которой передаете параметр pageNumber
. Эта функция вызывает функцию getArticles
и обновляет переменные состояния: stateArticles
и stateMeta
. Затем вы вызываете функцию udpateArticlesByPage
в методе onMount
, который запускается при первом отображении страницы или компонента Svelte и определяет HTML-шаблон для страницы index
. Наконец, вы перебираете в цикле найденные articles
и выводите список статей на текущей странице.
Теперь сохраните свой прогресс и перезапустите сервер разработки Svelte, выполнив следующую команду в терминале:
npm run dev
Зайдите на localhost:3000 и увидите в пользовательском интерфейсе статьи, полученные из Strapi:
Реализация элементов управления пагинацией в Svelte
Чтобы реализовать элементы управления пагинацией в Svelte, обновите HTML-шаблон в index.svelte
, добавив следующий код в блок else
:
<!-- ... -->
<h1>Strapi Articles ({stateMeta.pagination.total})</h1>
<div class="controls">
<div>
<label for="inputPageSize">Page Size</label>
<!-- 1 -->
<input
name="inputPageSize"
type="number"
bind:value={stateCurrentPageSize}
min="1"
max={stateMeta.pagination.total}
/>
<!-- 2 -->
<button
on:click|preventDefault={() => updateArticlesByPage(stateCurrentPageNumber)}
disabled={stateMeta.pagination.total <= stateCurrentPageSize}>Apply</button
>
</div>
</div>
<!-- ... -->
<div class="controls">
<!-- 3 -->
<button
on:click|preventDefault={() => updateArticlesByPage(--stateCurrentPageNumber)}
disabled={stateMeta.pagination.page === 1}>Previous</button
>
<!-- 4 -->
<div class="pagination">
{#each { length: stateMeta.pagination.pageCount } as _, p}
<button
on:click|preventDefault={() => updateArticlesByPage(p + 1)}
disabled={stateMeta.pagination.page === p + 1}>{p + 1}</button
>
{/each}
</div>
<!-- 5 -->
<button
on:click|preventDefault={() => updateArticlesByPage(++stateCurrentPageNumber)}
disabled={stateMeta.pagination.page === stateMeta.pagination.pageCount}>Next</button
>
</div>
<!-- ... -->
В приведенном выше коде вы определяете числовое поле input
для указания размера страницы и связываете его с переменной состояния stateCurrentPageSize
. Вы также определяете button
с обработчиком нажатия (on:click
) для вызова функции updateArticlesByPage
.
Далее вы определяете кнопку Previous button
, которая возвращает пользователя на одну страницу назад (--stateCurrentPageNumber
). Вы отключаете эту кнопку, если пользователь находится на первой странице, перебираете количество страниц (stateMeta.pagination.pageCount
) и создаете кнопку, которая переводит пользователя на нужную страницу. Наконец, вы определяете кнопку Next button
, которая переводит пользователя на одну страницу вперед (++stateCurrentPageNumber
) и отключаете эту кнопку, если пользователь находится на последней странице.
Далее, в качестве бонуса, добавьте следующие стили в конец index.svelte
:
<style>
* {
--light: #e2e2e2;
--light-dark: #a0a0a0;
--dark: #292929;
--disabled: #c4c3c3;
box-sizing: border-box;
font-family: 'Inter';
color: var(--dark);
}
section {
max-width: 100%;
padding-top: 1rem;
padding-bottom: 1rem;
}
.container {
max-width: 576px;
width: 100%;
margin: auto auto;
}
h1 {
font-size: 2rem;
margin-top: 0;
margin-bottom: 1.25rem;
}
h2 {
font-size: 1.5rem;
margin-top: 0;
margin-bottom: 0.5rem;
}
p {
margin-top: 0;
}
label {
font-size: 0.8rem;
}
.mb-4 {
margin-bottom: 2rem;
}
.controls {
display: flex;
justify-content: space-between;
align-items: center;
border-top: 0.0625rem solid var(--light);
border-bottom: 0.0625rem solid var(--light);
padding-top: 1rem;
padding-bottom: 1rem;
margin-bottom: 2rem;
}
.pagination {
display: flex;
flex-wrap: nowrap;
overflow: auto hidden;
border-radius: 0.125rem;
margin: auto 1rem;
}
.pagination::-webkit-scrollbar {
height: 0;
}
.pagination button {
border-radius: 0;
}
input {
vertical-align: middle;
outline: none;
border: 0.0625rem solid var(--light);
border-radius: 0.125rem;
padding: 0.25rem 0.5rem;
}
input:focus {
border: 0.0625rem solid var(--light-dark);
}
button {
vertical-align: middle;
cursor: pointer;
background: var(--dark);
outline: none;
border: 0.0625rem solid var(--dark);
color: #ffffff;
border-radius: 0.125rem;
padding: 0.25rem 0.5rem;
}
button:hover {
background: #000000;
}
button:disabled {
background: var(--disabled);
border: 0.0625rem solid var(--disabled);
cursor: not-allowed;
}
</style>
Поскольку вы можете стилизовать приложение по своему вкусу, приведенный выше код позволяет использовать существующие стили.
Наконец, сохраните свой прогресс и посетите localhost:3000, чтобы проверить элементы управления пагинацией в верхней и нижней части индексной страницы:
Тестирование пагинации
На localhost:3000 убедитесь, что функциональность пагинации работает так, как ожидается, поиграв с элементами управления пагинацией:
Теперь вы успешно завершили работу над функциональностью пагинации в Svelte и Strapi CMS.
Заключение
В этом руководстве вы научились работать с пагинацией Strapi и реализовали пользовательский интерфейс элементов управления пагинацией, создав фронтенд в Svelte. Вы можете добавить пагинацию в конечные точки API, которые возвращают огромное количество данных, и создавать более качественные и производительные приложения.
Пагинация может показаться сложной темой, но как только вы пройдете через ее реализацию, вы сможете использовать базовые техники в различных комбинациях фронтенда и бэкенд-фреймворков.
Весь исходный код этого руководства доступен в этом репозитории GitHub.