Создание Tabs в React
Табы(вкладки) — это компоненты пользовательского интерфейса, которые визуализируют и отображают подразделы для пользователей; они упорядочивают контент по категориям для легкого доступа и делают ваши приложения более чистыми, экономя место. Вкладки являются распространенным компонентом пользовательского интерфейса, и разработчику важно понимать, как их реализовать. Эта статья покажет вам, как создать компонент табов в React и создать функции, которые будут обрабатывать переключение вкладок.
Создание компонента вкладки в React
Прежде чем мы создадим компонент вкладки в нашем приложении React, нам нужно удалить шаблон CRA. В исходной папке находим файлы App.css и Index.css
и очищаем написанные там стили (мы создадим свои).
Откройте файл App.js
, удалите все, что заключено в div с именем класса приложения, и удалите строку, которая импортирует логотип SVG:
import logo from './logo.svg';
После очистки файл App.js
должен выглядеть так:
import './App.css'; function App() { return ( <div className="App"> </div> ); } export default App;
В своей src
папке создайте новую папку с именем Components
, в которой будут размещаться компоненты, которые мы создадим. Затем создайте еще одну подпапку с именем TabComponent
, в которой будет находиться файл Tabs.js
:
src +-- Components +-- TabComponent +-- Tabs.js
Теперь добавьте в файл Tab.js
следующий код , чтобы показать, что мы его экспортируем:
import React from "react"; const Tabs = () => { return ( <div className="Tabs"> <p>Hello Tab works</p> </div> ); }; export default Tabs; import "./App.css"; import Tabs from "./Components/TabComponent/Tabs"; function App() { return ( <div className="App"> <Tabs /> </div> ); } export default App;
Далее нам нужно импортировать файл Tabs.js
в файл App.js :
import "./App.css"; import Tabs from "./Components/TabComponent/Tabs"; function App() { return ( <div className="App"> <Tabs /> </div> ); } export default App;
Если он не отображается на вашей стороне, убедитесь, что вы правильно импортируете и экспортируете компонент.
Добавьте следующий код в ваш файл Tabs.js
:
import React from "react"; const Tabs = () => { return ( <div className="Tabs"> {/* Tab nav */} <ul className="nav"> <li>Tab 1</li> <li>Tab 2</li> </ul> <div className="outlet"> {/* content will be shown here */} </div> </div> ); }; export default Tabs;
В приведенном выше коде у нас есть два раздела, завернутые в родительские вкладки div
: the nav
и outlet
. nav
обрабатывает навигацию между вкладками, а outlet
отображает содержимое активной вкладки.
Это будет выглядеть уродливо, когда вы просматриваете его в своем браузере, и это не будет иметь никакого смысла, но позже мы добавим немного CSS.
Следующим шагом будет создание компонентов для каждой вкладки. В этом руководстве мы сначала создадим две, а затем расширим код для поддержки множества вкладок. Во-первых, давайте напишем код для создания двух компонентов вкладок.
В Components
папке создайте новую папку и назовите ее AllTabs
. Затем создайте два файла и назовите их соответственно FirstTab.js и SecondTab.js
:
src +-- Components +-- AllTabs +-- FirstTab.js +-- SecondTab.js
Файл firstTab.js
содержит код того, что должно отображаться на первой вкладке, и содержит то, что он должен отображать на второй вкладке secondTab.js
:
// FirstTab.js import React from "react"; const FirstTab = () => { return ( <div className="FirstTab"> <p>First Tab!! Hurray!!</p> {/* First tab content will go here */} </div> ); }; export default FirstTab; // SecondTab.js import React from "react"; const SecondTab = () => { return ( <div className="SecondTab"> <p>Second Tab!! Hurray!!</p> {/* Second tab content will go here */} </div> ); }; export default SecondTab;
Это все, что нам нужно на данный момент. Перейдем к стилизации.
Стилизация компонентов вкладки React
Нам нужно добавить некоторые стили к тому, что мы создали до сих пор. Ради этого руководства мы будем записывать все стили в файл App.css
. Вы можете создавать отдельные файлы стилей для каждого компонента, но не забудьте их импортировать.
Во-первых, давайте удалим стили по умолчанию, которые браузер добавляет к нашим элементам, потому что мы хотим сами контролировать поля и отступы. Используя селектор звездочки в CSS, мы можем выбрать каждый элемент в веб-приложении и стилизовать его по своему усмотрению.
Мы сбросим все поля и отступы на ноль и предоставим каждому элементу a box-sizingborder-box
, включая все отступы и границы, равную ширине элемента:
/* Remove browser defaults */ * { box-sizing: border-box; padding: 0; margin: 0; } ...
Теперь давайте стилизуем нашу обертку. Это демонстрационное приложение, так что это будет одна страница, занимающая всю ширину и высоту экрана. Нам также нужно, чтобы все элементы в приложении были центрированы посередине:App.js
// Style App.js wrapper .App { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } ...
Далее давайте стилизуем наш Tabs
компонент. Стиль будет простым; просто добавьте немного полей и отступов для интервалов и цвет фона, чтобы он выглядел красиво:
/* Tab Container */ .Tabs { width: 80%; height: auto; min-height: 400px; background: #053742; margin: 3.5rem auto 1.5rem; padding: 2rem 1rem; color: #E8F0F2; border-radius: 2rem; @media (max-width: 769px) { padding: 2rem 0; } } ...
Двигаясь дальше, нам нужно отделить наши навигационные кнопки от тела вкладки, чтобы пользователи могли быстро видеть навигатор и переключаться между вкладками:
/* Tab Navigation */ ul.nav { width: 60%; margin: 0 auto 2rem; display: flex; align-items: center; justify-content: space-between; border: 1px solid #39A2DB; border-radius: 2rem; padding-left: 0px; @media (max-width: 768px) { width: 90%; } } ul.nav li { width: 50%; padding: 1rem; list-style: none; text-align: center; cursor: pointer; transition: all 0.7s; border-bottom-left-radius: 2rem; border-top-left-radius: 2rem; } ul.nav li:nth-child(2) { border-radius: 0; border-bottom-right-radius: 2rem; border-top-right-radius: 2rem; } ul.nav li:hover { background: rgba(50, 224, 196, 0.15); } ul.nav li.active { background: #39A2DB; } ...
Наконец, давайте стилизуем содержимое нашей демонстрационной вкладки. В этом посте мы будем использовать p
элемент тега для отображения фиктивных данных:
/* First and Second Tab Styles */ .FirstTab p, .SecondTab p { font-size: 2rem; text-align: center; }
Вот как должен выглядеть ваш окончательный файл App.css
:
// App.css /* Remove browser defaults */ * { box-sizing: border-box; padding: 0; margin: 0; } // Style App.js wrapper .App { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } /* Tab Container */ .Tabs { width: 80%; height: auto; min-height: 400px; background: #053742; margin: 3.5rem auto 1.5rem; padding: 2rem 1rem; color: #E8F0F2; border-radius: 2rem; @media (max-width: 769px) { padding: 2rem 0; } } /* Tab Navigation */ ul.nav { width: 60%; margin: 0 auto 2rem; display: flex; align-items: center; justify-content: space-between; border: 1px solid #39A2DB; border-radius: 2rem; @media (max-width: 768px) { width: 90%; } } ul.nav li { width: 50%; padding: 1rem; list-style: none; text-align: center; cursor: pointer; transition: all 0.7s; border-bottom-left-radius: 2rem; border-top-left-radius: 2rem; } ul.nav li:nth-child(2) { border-radius: 0; border-bottom-right-radius: 2rem; border-top-right-radius: 2rem; } ul.nav li:hover { background: rgba(50, 224, 196, 0.15); } ul.nav li.active { background: #39A2DB; } /* First and Second Tab Styles */ .FirstTab p, .SecondTab p { font-size: 2rem; text-align: center; }
Перезагрузите страницу в браузере, и вы должны увидеть что-то похожее на изображение ниже:
Перезагрузите страницу в браузере, и вы должны увидеть что-то похожее на следующее превью:
Вкладки пока не будут переключать содержимое, но они будут отображать анимацию при наведении из-за кода CSS, который мы добавили. Давайте добавим код для реализации логики переключения вкладок.
Использование useState
для управления состоянием вкладки React
Когда вы просмотрите стили выше, вы заметите, что у нас есть определенный стиль для активной вкладки, но как мы узнаем, какая вкладка активна? Для этого мы будем использовать React Hook useState
для управления нашим состоянием.
Во-первых, нам нужно импортировать useState
хук из библиотеки React и установить активные вкладки по умолчанию из файла Tabs.js
:
import React, { useState } from "react"; const Tabs = () => { const [activeTab, setActiveTab] = useState("tab1"); // ... the previous codes } export default Tabs;
Далее мы проверим, активна ли вкладка, и добавим active
в нее класс. В противном случае мы удалим active
класс:
// Tab nav <ul className="nav"> <li className={activeTab === "tab1" ? "active" : ""}>Tab 1</li> <li className={activeTab === "tab2" ? "active" : ""}>Tab 2</li> </ul>
Когда вы просматриваете его из своего браузера, он должен выглядеть так:
Вкладка 1 имеет цвет фона, потому что это активная вкладка. Теперь давайте сообщим React DOM, какой контент показывать, когда вкладка активна.
Во-первых, нам нужно импортировать наши файлы первой и второй вкладок в компонент вкладок.
import FirstTab from "../AllTabs/FirstTab"; import SecondTab from "../AllTabs/SecondTab";
Теперь добавьте импортированные компоненты в outlet
div:
<div className="outlet"> <FirstTab /> <SecondTab /> </div>
Когда вы откроете браузер, вы увидите небольшой хаос (содержимое обеих вкладок отображается на вкладке 1), но не волнуйтесь, скоро мы наведем порядок.
Точно так же, как мы проверили навигацию, чтобы установить активный класс на активную ссылку навигации, мы реализуем тот же подход к outlet
:
<div className="outlet"> {activeTab === "tab1" ? <FirstTab /> : <SecondTab />} </div>
Здесь мы говорим React DOM показывать первую вкладку только тогда, когда активна вкладка "tab1"
. В противном случае отображается вторая вкладка.
Создание функции для управления переключением вкладок в React
При нажатии на любую из вкладок ничего не происходит. Давайте изменим это.
Эта функция сообщит React DOM, какое содержимое вкладки мы хотим отображать, когда вкладка активна:
// Functions to handle Tab Switching const handleTab1 = () => { // update the state to tab1 setActiveTab("tab1"); }; const handleTab2 = () => { // update the state to tab2 setActiveTab("tab2"); };
Это довольно чисто и просто; вы могли бы написать это даже одной строкой, но для простоты оставим это так.
Так что же делает код? Первая функция устанавливает и обновляет активное состояние вкладки в "tab1"
любое время при ее вызове, а вторая функция делает то же самое для "tab2"
.
Следующим шагом является пометка этих функций для наших навигационных ссылок, чтобы они вызывались и выполнялись при нажатии соответствующей навигационной ссылки:
{/* Tab nav */} <ul className="nav"> <li className={activeTab === "tab1" ? "active" : ""} onClick={handleTab1} > Tab 1 </li> <li className={activeTab === "tab2" ? "active" : ""} onClick={handleTab2} > Tab 2 </li> </ul>
Посмотрите на следующий полный исходный код компонента Tabs.js после вышеуказанных изменений:
import React, { useState } from "react"; import FirstTab from "../AllTabs/FirstTab"; import SecondTab from "../AllTabs/SecondTab"; const Tabs = () => { const [activeTab, setActiveTab] = useState("tab1"); // Functions to handle Tab Switching const handleTab1 = () => { // update the state to tab1 setActiveTab("tab1"); }; const handleTab2 = () => { // update the state to tab2 setActiveTab("tab2"); }; return ( <div className="Tabs"> <ul className="nav"> <li className={activeTab === "tab1" ? "active" : ""} onClick={handleTab1} > Tab 1 </li> <li className={activeTab === "tab2" ? "active" : ""} onClick={handleTab2} > Tab 2 </li> </ul> <div className="outlet"> {activeTab === "tab1" ? <FirstTab /> : <SecondTab />} </div> </div> ); }; export default Tabs;
Вот и все! Теперь вы можете переключаться между вкладками, щелкая соответствующую навигационную ссылку, как показано ниже:
Расширение кода для поддержки большего количества вкладок
Что делать, если нам нужно расширить код для отображения третьей вкладки? Существует два основных подхода к добавлению еще одной вкладки. Мы можем создать другой компонент с новым содержимым вкладки, как мы создали SecondTab
компонент с той же структурой кода.
Мы можем реорганизовать наш проект, чтобы он поддерживал множество компонентов вкладок. Если мы создадим новый компонент для каждой вкладки и будем следовать существующей структуре кода, исходный код станет менее управляемым из-за повторяющегося кода. Поэтому мы можем реорганизовать существующий проект, чтобы он поддерживал множество вкладок.
Нам нужно использовать следующий фрагмент CSS, чтобы сделать существующий код CSS гибким для отображения более двух вкладок.
ul.nav li:first-child { border-bottom-left-radius: 2rem; border-top-left-radius: 2rem; } ul.nav li:last-child { border-bottom-right-radius: 2rem; border-top-right-radius: 2rem; }
Приведенный выше фрагмент CSS стилизует только первый и последний радиус вкладки независимо от того, сколько вкладок мы используем. Замените содержимое файла App.css
следующим кодом CSS.
/* Remove browser defaults */ * { box-sizing: border-box; padding: 0; margin: 0; } /* Style App.js wrapper */ .App { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } /* Tab Container */ .Tabs { width: 80%; height: auto; min-height: 400px; background: #053742; margin: 3.5rem auto 1.5rem; padding: 2rem 1rem; color: #E8F0F2; border-radius: 2rem; @media (max-width: 769px) { padding: 2rem 0; } } /* Tab Navigation */ ul.nav { width: 60%; margin: 0 auto 2rem; display: flex; align-items: center; justify-content: space-between; border: 1px solid #39A2DB; border-radius: 2rem; padding-left: 0px; @media (max-width: 768px) { width: 90%; } } ul.nav li { width: 50%; padding: 1rem; list-style: none; text-align: center; cursor: pointer; transition: all 0.7s; } ul.nav li:first-child { border-bottom-left-radius: 2rem; border-top-left-radius: 2rem; } ul.nav li:last-child { border-bottom-right-radius: 2rem; border-top-right-radius: 2rem; } ul.nav li:hover { background: rgba(50, 224, 196, 0.15); } ul.nav li.active { background: #39A2DB; } /* Tab Content Styles */ .TabContent { font-size: 2rem; text-align: center; }
Теперь мы собираемся реорганизовать нашу структуру кода JavaScript, создав два новых компонента:
TabNavItem
: компонент для представления элемента навигации по вкладкамTabContent
: отображает содержимое для каждой вкладки, и мы можем передать любой контент в качестве дочерних компонентов.
Создайте каталог с именем V2
внутри существующего Components
каталога для хранения новых компонентов. Добавьте следующий код Components/TabNavItem.js
, чтобы определить компонент TabNavItem
.
import React from "react"; const TabNavItem = ({ id, title, activeTab, setActiveTab }) => { const handleClick = () => { setActiveTab(id); }; return ( <li onClick={handleClick} className={activeTab === id ? "active" : ""}> { title } </li> ); }; export default TabNavItem;
Вышеупомянутый компонент отображает элемент навигации по вкладкам с li
элементом HTML.
Здесь мы динамически устанавливаем активный класс CSS в соответствии с activeTab
реквизитом и текущим идентификатором вкладки. Также мы используем setActiveTab
обратный вызов для переключения текущей выбранной вкладки.
Затем добавьте в файл следующий код Components/TabContent.js
, чтобы определить компонент TabContent.
import React from "react"; const TabContent = ({id, activeTab, children}) => { return ( activeTab === id ? <div className="TabContent"> { children } </div> : null ); }; export default TabContent;
Обратите внимание, что мы условно визуализируем компонент на основе свойства id
и activeTab
свойства. Кроме того, мы отображаем все предоставленные дочерние компоненты { children }
внутри компонента, используя синтаксис шаблона.
Теперь атомарные строительные блоки компонента динамической вкладки готовы. Давайте проведем рефакторинг существующего Tab
источника компонентов, используя вновь созданные (V2) компоненты. Добавьте в файл Components/Tabs.js
следующий код :
import React, { useState } from "react"; import TabNavItem from "../V2/TabNavItem"; import TabContent from "../V2/TabContent"; const Tabs = () => { const [activeTab, setActiveTab] = useState("tab1"); return ( <div className="Tabs"> <ul className="nav"> <TabNavItem title="Tab 1" id="tab1" activeTab={activeTab} setActiveTab={setActiveTab}/> <TabNavItem title="Tab 2" id="tab2" activeTab={activeTab} setActiveTab={setActiveTab}/> <TabNavItem title="Tab 3" id="tab3" activeTab={activeTab} setActiveTab={setActiveTab}/> </ul> <div className="outlet"> <TabContent id="tab1" activeTab={activeTab}> <p>Tab 1 works!</p> </TabContent> <TabContent id="tab2" activeTab={activeTab}> <p>Tab 2 works!</p> </TabContent> <TabContent id="tab3" activeTab={activeTab}> <p>Tab 3 works!</p> </TabContent> </div> </div> ); }; export default Tabs;
Проверьте свой браузер. Вы увидите три рабочие вкладки, как показано в следующем предварительном просмотре.
Помните, ранее я упоминал, что мы собираемся реализовать управляемый исходный код вместо того, чтобы писать повторяющийся код? Вот как легко добавить четвертую вкладку. Добавьте следующую строку в контейнер навигации сразу после элемента навигации третьей вкладки.
<TabNavItem title="Tab 4" id="tab4" activeTab={activeTab} setActiveTab={setActiveTab}/>
Затем добавьте содержимое вкладки, как показано ниже, сразу после содержимого третьей вкладки.
<TabContent id="tab4" activeTab={activeTab}> <p>tab4 works!</p> </TabContent>
Смотрите четвертую вкладку в браузере.
Кроме того, вы можете повторно использовать предыдущие FirstTab
и SecondTab
компоненты тоже. Например, посмотрите на следующий код:
import React, { useState } from "react"; import FirstTab from "../AllTabs/FirstTab.js"; import SecondTab from "../AllTabs/SecondTab.js"; import TabNavItem from "../V2/TabNavItem"; import TabContent from "../V2/TabContent"; const Tabs = () => { const [activeTab, setActiveTab] = useState("tab1"); return ( <div className="Tabs"> <ul className="nav"> <TabNavItem title="Tab 1" id="tab1" activeTab={activeTab} setActiveTab={setActiveTab}/> <TabNavItem title="Tab 2" id="tab2" activeTab={activeTab} setActiveTab={setActiveTab}/> </ul> <div className="outlet"> <TabContent id="tab1" activeTab={activeTab}> <FirstTab/> </TabContent> <TabContent id="tab2" activeTab={activeTab}> <SecondTab/> </TabContent> </div> </div> ); }; export default Tabs;
Приведенный выше код покажет содержимое FirstTab
и SecondTab
компоненты.
Создание вкладок с помощью библиотеки react-tabs
На этом этапе вы уже знаете, как создавать компоненты вкладок React с нуля без сторонней библиотеки. Но нам пришлось написать код для отображения и установки текущей выбранной вкладки, управляя состоянием компонента вкладки.
Внедрение компонентов вкладок с нуля дает нам полную гибкость и свободу, но это может занять много времени для создания современной культуры быстрой разработки приложений.
Таким образом, вы можете использовать полнофункциональную библиотеку для создания компонентов вкладок в своих приложениях React. Библиотека react-tabs — популярная библиотека для создания компонентов вкладок.
Теперь мы собираемся воссоздать предыдущее приложение, используя библиотеку react-tabs. Сначала установите библиотеку react-tabs с расширением npm install react-tabs
. Затем добавьте следующее содержимое в App.js.
import { Tab, Tabs, TabList, TabPanel } from "react-tabs"; import "./App.css"; function App() { return ( <div className="App"> <Tabs className="Tabs"> <TabList> <Tab>Tab 1</Tab> <Tab>Tab 2</Tab> <Tab>Tab 3</Tab> </TabList> <TabPanel> <p>Tab 1 works!</p> </TabPanel> <TabPanel> <p>Tab 2 works!</p> </TabPanel> <TabPanel> <p>Tab 3 works!</p> </TabPanel> </Tabs> </div> ); } export default App;
Обратите внимание, что здесь мы импортируем некоторые предварительно созданные компоненты из библиотеки react-tabs, чтобы заставить наш компонент вкладок работать. Библиотека будет автоматически генерировать идентификаторы вкладок, поэтому нам не нужно id
использовать prop
.
Если вы проверите браузер сейчас, вы заметите, что на вкладках отсутствуют стили CSS. Это связано с тем, что текущие классы CSS App.css
не соответствуют должным образом внутренним классам CSS библиотеки. Поэтому обновите файл App.css
, добавив:
/* Remove browser defaults */ * { box-sizing: border-box; padding: 0; margin: 0; } /* Style App.js wrapper */ .App { width: 100vw; height: 100vh; display: flex; align-items: center; justify-content: center; overflow: hidden; } /* Tab Container */ .Tabs { width: 80%; height: auto; min-height: 400px; background: #053742; margin: 3.5rem auto 1.5rem; padding: 2rem 1rem; color: #E8F0F2; border-radius: 2rem; } .react-tabs { -webkit-tap-highlight-color: transparent; } .react-tabs__tab-list { width: 60%; margin: 0 auto 2rem; display: flex; align-items: center; justify-content: space-between; border: 1px solid #39A2DB; border-radius: 2rem; padding-left: 0px; } .react-tabs__tab { width: 50%; padding: 1rem; list-style: none; text-align: center; cursor: pointer; transition: all 0.7s; } .react-tabs__tab--selected { background: #39A2DB; } .react-tabs__tab--disabled { color: GrayText; cursor: default; } .react-tabs__tab:hover { background: rgba(50, 224, 196, 0.15); } .react-tabs__tab:first-child { border-bottom-left-radius: 2rem; border-top-left-radius: 2rem; } .react-tabs__tab:last-child { border-bottom-right-radius: 2rem; border-top-right-radius: 2rem; } .react-tabs__tab-panel { display: none; } .react-tabs__tab-panel--selected { display: block; font-size: 2rem; text-align: center; }
Заключение
Отличная работа, чтобы зайти так далеко! В этом руководстве мы создадли компонент вкладки React, используя React Hooks для управления активным состоянием вкладки и создадим простые функции для управления и обработки переключения вкладок. Кроме того, мы провели рефакторинг кодовой базы компонента вкладок, чтобы он поддерживал множество вкладок, и использовали библиотеку react-tabs, чтобы ускорить разработку компонента вкладок React.