Разбиение на страницы, также называемое пейджингом, делит информацию на веб-странице на разные страницы, по которым можно перемещаться с помощью кнопок или нумерованного списка. Разбивка на страницы может улучшить организацию вашего веб-сайта, улучшить UX и, в конечном итоге, повысить общий рейтинг. Вы можете добавить нумерацию страниц в веб-приложение, настольное приложение или мобильное приложение и реализовать его либо на стороне клиента, либо на стороне сервера.
В этом руководстве мы будем использовать React и Tailwind CSS для создания двух разных типов компонентов разбивки на страницы на стороне клиента. Один будет использовать кнопки для навигации, а другой будет использовать нумерованный список. Давайте начнем!
Использование Tailwind CSS в проекте React
Сначала настройте новый проект React на локальном компьютере, выполнив следующую команду:
npx create-react-app my-app cd my-app
Далее мы установим Tailwind CSS и несколько других зависимостей в наш каталог:
npm install -D tailwindcss@npm:@tailwindcss/postcss7-compat postcss@^7 autoprefixer@^9
Нам нужно установить приложение Create React, однако оно не может изначально переопределить конфигурацию PostCSS. Поэтому мы установим CRACO, уровень конфигурации для CRA, в дополнение к нескольким другим скриптам в нашем package.json
:
npm install @craco/craco
Раздел scripts
вашего проекта должен выглядеть как блок кода ниже:
"scripts": { "start": "craco start", "build": "craco build", "test": "craco test", "eject": "react-scripts eject" },
Теперь давайте создадим новый файл с именем craco.config.js
и добавим Tailwind CSS и autoprefixer
в качестве плагинов PostCSS:
module.exports = { style: { postcss: { plugins: [require("tailwindcss"), require("autoprefixer")], }, }, };
Далее мы создадим файл с именем tailwind.config.js
с помощью следующей команды:
npx tailwindcss-cli@latest init
Чтобы завершить настройку Tailwind CSS, добавьте следующий код в файл default index.css
:
@tailwind base; @tailwind components; @tailwind utilities;
Теперь, когда наш проект полностью настроен, мы можем приступить к созданию компонентов разбиения на страницы!
Структурирование компонента пагинации
Наш проект будет следовать структуре на изображении ниже. Давайте подробно рассмотрим некоторые из этих файлов и папок:
Pagination.js
будет содержать логику для обработки и отображения компонента нумерации страниц. Код в этой папке будет отличаться для каждого из двух типов нумерации страниц, поэтому мы еще раз рассмотрим его позже.
Posts.js
— это статический элемент POST
, который будет получать случайные данные из API. Данные и структура Posts.js
, как показано в блоке кода ниже, будут одинаковыми для обоих типов разбиения на страницы:
import React from "react"; const Posts = ({ posts, loading }) => { if (loading) { return <h2>Loading...</h2>; } return ( <div> <ul> {posts.map((post) => ( <li key={post.id} className='text-gray-700 font-semibold text-xl mb-2 border p-2' > {post.title} </li> ))} </ul> </div> ); }; export default Posts;
Разбиение на страницы с помощью кнопок навигации
Первый тип компонента разбивки на страницы, который мы создадим, использует кнопки «Далее» и «Назад» для навигации по данным на веб-странице. Наш файл App.js
будет выглядеть как блок кода ниже:
import React, { useState, useEffect } from "react"; import Posts from "./Posts"; import Pagination from "./Pagination"; import axios from "axios"; const App = () => { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [postsPerPage] = useState(10); useEffect(() => { const fetchPosts = async () => { setLoading(true); const res = await axios.get("https://jsonplaceholder.typicode.com/posts"); setPosts(res.data); setLoading(false); }; fetchPosts(); }, []); // Get current posts const indexOfLastPost = currentPage * postsPerPage; const indexOfFirstPost = indexOfLastPost - postsPerPage; const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost); // Change page const paginateFront = () => setCurrentPage(currentPage + 1); const paginateBack = () => setCurrentPage(currentPage - 1); return ( <div> <Posts posts={currentPosts} /> <Pagination postsPerPage={postsPerPage} totalPosts={posts.length} paginateBack={paginateBack} paginateFront={paginateFront} currentPage={currentPage} /> </div> ); }; export default App;
В нашем файле App.js
данные в posts
поступают из бэкенда. Давайте рассмотрим некоторые функции в нашем компоненте разбивки на страницы, которые используют эти данные:
currentPage
: указывает пользователю, на какой странице он находится в данный момент.postsPerPage
: общее количество сообщений, которые будут отображаться на странице.currentPosts
: массив сообщений для текущей страницы
Чтобы получить currentPosts
, нам нужно передать indexOfFirstPost
и indexOfLastPost
функции slice()
.
Для перемещения вперед и назад между страницами мы будем использовать paginateFront
и paginateBack
. Эти функции просто увеличивают или уменьшают currentPage
, и в результате вычисляется currentPosts
.
Pagination.js
файл
Теперь давайте посмотрим на наш файл Pagination.js
:
import React from "react"; export default function Pagination({ postsPerPage, totalPosts, paginateFront, paginateBack, currentPage, }) { return ( <div className='py-2'> <div> <p className='text-sm text-gray-700'> Showing <span className='font-medium'>{currentPage * postsPerPage - 10}</span> to <span className='font-medium'> {currentPage * postsPerPage} </span> of <span className='font-medium'> {totalPosts} </span> results </p> </div> <nav className='block'></nav> <div> <nav className='relative z-0 inline-flex rounded-md shadow-sm -space-x-px' aria-label='Pagination' > <a onClick={() => { paginateBack(); }} href='#' className='relative inline-flex items-center px-2 py-2 rounded-l-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' > <span>Previous</span> </a> <a onClick={() => { paginateFront(); }} href='#' className='relative inline-flex items-center px-2 py-2 rounded-r-md border border-gray-300 bg-white text-sm font-medium text-gray-500 hover:bg-gray-50' > <span>Next</span> </a> </nav> </div> </div> ); }
Компонент разбивки на страницы принимает реквизиты, которые отображают текущую информацию о нашей странице, а служебные классы Tailwind CSS устраняют необходимость во внешнем CSS.
Когда мы запустим приведенный выше код, мы получим следующий результат:
На изображении выше наш компонент разбивки на страницы отображает от 10 до 20 результатов из 100. Давайте нажмем кнопку «Далее», чтобы посмотреть, что произойдет:
Теперь мы можем видеть результаты с 20 по 30. Когда мы нажмем кнопку «Назад», мы вернемся к результатам с 10 по 20:
Разбивка на страницы с помощью нумерованного списка
Второй компонент разбивки на страницы, который мы создадим, использует для навигации нумерованный список вместо кнопок «Далее» и «Назад». Нам нужно внести несколько изменений в наш файл App.js
и реквизиты, которые отправляются в компонент разбивки на страницы.
Обновите файл App.js
, чтобы он выглядел как блок кода ниже:
import React, { useState, useEffect } from "react"; import Posts from "./Posts"; import Pagination from "./Pagination"; import axios from "axios"; const App = () => { const [posts, setPosts] = useState([]); const [loading, setLoading] = useState(false); const [currentPage, setCurrentPage] = useState(1); const [postsPerPage] = useState(10); useEffect(() => { const fetchPosts = async () => { setLoading(true); const res = await axios.get("https://jsonplaceholder.typicode.com/posts"); setPosts(res.data); setLoading(false); }; fetchPosts(); }, []); // Get current posts const indexOfLastPost = currentPage * postsPerPage; const indexOfFirstPost = indexOfLastPost - postsPerPage; const currentPosts = posts.slice(indexOfFirstPost, indexOfLastPost); // Change page const paginate = (pageNumber) => setCurrentPage(pageNumber); return ( <div> <Posts posts={currentPosts} /> <Pagination postsPerPage={postsPerPage} totalPosts={posts.length} paginate={paginate} currentPage={currentPage} /> </div> ); }; export default App;
Теперь у нас есть одна функция разбивки на страницы, которая только обновляет currentPage
для установки currentPosts
, в отличие от передачи indexOfFirstPost
и indexOfLastPost
, как мы делали для нашего предыдущего компонента разбиения на страницы.
Давайте посмотрим на код нашего компонента разбивки на страницы, который использует нумерованный список:
import React from "react"; export default function Pagination({ postsPerPage, totalPosts, paginate, currentPage, }) { const pageNumbers = []; for (let i = 1; i <= Math.ceil(totalPosts / postsPerPage); i++) { pageNumbers.push(i); } return ( <div className='py-2'> <div> <p className='text-sm text-gray-700'> Showing <span className='font-medium'> {" "} {currentPage * postsPerPage - 10}{" "} </span> to <span className='font-medium'> {currentPage * postsPerPage} </span> of <span className='font-medium'> {totalPosts} </span> results </p> </div> <nav className='block'> <ul className='flex pl-0 rounded list-none flex-wrap'> <li> {pageNumbers.map((number) => ( <a onClick={() => { paginate(number); }} href='#' className={ currentPage === number ? "bg-blue border-red-300 text-red-500 hover:bg-blue-200 relative inline-flex items-center px-4 py-2 border text-sm font-medium" : "bg-white border-gray-300 text-gray-500 hover:bg-blue-200 relative inline-flex items-center px-4 py-2 border text-sm font-medium" } > {number} </a> ))} </li> </ul> </nav> </div> ); }
Мы создали массив, который динамически вычисляет количество страниц, необходимых для заданного объема данных. Затем он добавляет данные внутрь массива pageNumbers
.
Теперь мы создадим неупорядоченный список, который отображает элементы списка, перебирая наш массив pageNumbers
. Создание неупорядоченного списка создаст компонент навигации для страниц, который будет выглядеть следующим образом:
Внутри функции map
мы прикрепили обработчик кликов к каждому номеру страницы. При нажатии каждая кнопка будет переходить на определенную страницу. currentPage
будет установлено в нашем файле App.js
, и мы получим обновленный массив currentPosts
, который будет отображать требуемый контент во внешнем интерфейсе.
Давайте выделим активную страницу внутри нашего компонента навигации по страницам:
<a onClick={() => { paginate(number); }} href='#' className={ currentPage === number ? "bg-blue border-red-300 text-red-500 hover:bg-blue-200 relative inline-flex items-center px-4 py-2 border text-sm font-medium" : "bg-white border-gray-300 text-gray-500 hover:bg-blue-200 relative inline-flex items-center px-4 py-2 border text-sm font-medium" } > {number} </a>
Для тега <a>
мы устанавливаем разные классы CSS Tailwind на основе проверки. Если pageNumber
для нашего тега <a>
равно currentPage
, мы будем отличать его от других тегов <a>
, придав ему красную рамку и цвет шрифта.
Давайте снова запустим проект, чтобы увидеть результат. На первой странице мы увидим следующее:
Когда мы перейдем на десятую страницу, мы увидим следующее:
Заключение
Теперь у вас должно быть полное представление о нумерации страниц! Разбивка на страницы — отличная функция для улучшения UX вашего приложения. Мы рассмотрели два метода реализации разбивки на страницы в приложении React с помощью Tailwind CSS, кнопок навигации и нумерованного списка. Лучший выбор будет зависеть от характера вашего приложения и ваших данных.
Дополнительные материалы на PlainEnglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Подпишитесь на нас в Twitter, LinkedIn, YouTube и Discord.