Глава 1. Пошаговое руководство по созданию шаблона электронной коммерции React с использованием Tailwind CSS.
Меня вдохновляет шаблон списка продуктов электронной коммерции Nordic Store. Этот шаблон использует Tailwind CSS и был создан Tailwind Toolbox.
Шаблон Nordic Store — это статический CSS-шаблон Tailwind. Поэтому я планировал создать динамический шаблон Nordic Store с помощью React.
В этой серии блогов мы собираемся создать динамический шаблон электронной коммерции с использованием React и Tailwind CSS.
Зачем использовать Tailwind CSS
Tailwind — это ориентированная на утилиты CSS-инфраструктура для быстрого создания настраиваемых пользовательских интерфейсов. Просто служебные классы помогают вам стилизовать веб-приложения. Таким образом, мы можем сделать все ваши стили с помощью служебных классов и без сенсорных таблиц стилей.
Также готовые компоненты доступны на Tailwind UI.
Глава 1: Начало
В этой главе мы собираемся выполнить следующие задачи:
- Создайте новое приложение React
- Установка Tailwind CSS и React Router
- Установка зависимостей
- Создание базового компонента макета
- Создание домашней страницы
- Создание статической домашней страницы Nordic Store
Создайте новое приложение React
Создайте свое новое приложение React, используя create-react-app
Terminal
npx create-react-app tailwindcss-nordic-store cd tailwindcss-nordic-store
Установка Tailwind CSS и React Router
Установка Tailwind CSS объясняется в документе Tailwind CSS здесь
Сначала установите tailwindcss
, postcss
и autoprefixer
, а затем запустите команду инициализации, чтобы сгенерировать tailwind.config.js
и postcss.config.js
.
Terminal
npm install -D tailwindcss postcss autoprefixer npx tailwindcss init -p
Откройте файл tailwind.config.js
и добавьте все пути к файлам шаблона.
tailwind.config.js
module.exports = { content: [ "./src/**/*.{js,jsx,ts,tsx}", ], theme: { extend: {}, }, plugins: [], }
Добавьте директивы @tailwind
для каждого из слоев Tailwind в ваш файл src/index.css
.
src/index.css
@tailwind base; @tailwind components; @tailwind utilities;
Мы успешно установили Tailwind CSS в ваше приложение. Для динамических шаблонов нам нужны разные страницы, поэтому мы собираемся установить React Router в ваше приложение.
Terminal
npm install react-router-dom@6
Установка зависимостей
Безголовый пользовательский интерфейс для управления всем интерактивным поведением и Heroicons для значков, поэтому вам нужно будет добавить эти две библиотеки в свое приложение.
Terminal
npm install @headlessui/react @heroicons/react
Создание базового компонента макета
Основные этапы создания макета опубликованы в моем предыдущем блоге Создайте свой собственный компонент макета в React.
Загрузите приложение и скопируйте папку компонентов в свой https://github.com/balajidharma/react-basic-layout/archive/refs/heads/master.zip.
Обновите свой App.js и включите наш макет в ваш index.js:
src/App.js
import './App.css';function App() { return ( <div className="App"> Hello world! </div> ); }export default App;
src/index.js
import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; import Layout from './components/Layout/Layout';ReactDOM.render( <Layout> <App /> </Layout>, document.getElementById('root') );
Теперь запустите свое приложение и просмотрите основные разделы «Заголовок», «Нижний колонтитул» и «Содержимое» браузера.
Terminal
npm start
Browser
Создание домашней страницы
Пришло время создать нашу страницу с помощью React Router. Создайте новую папку pages
в папке src
. Создайте компонент Home
внутри папки pages
src/pages/Home.js
import React from 'react'; class Home extends React.Component { render() { return ( <div> Home page </div> ); } } export default Home;
Компонент React class
, используемый для нашего приложения. Подробнее о компонентах React здесь.
Также прочтите Различия между функциональными компонентами и классовыми компонентами в React.
Включите React Router и домашнюю страницу в виде файла index.js
. Также мы собираемся удалить app.js
.
src/index.js
import React from 'react'; import ReactDOM from 'react-dom'; import { BrowserRouter, Routes, Route } from "react-router-dom"; import './index.css'; import Layout from './components/Layout/Layout'; import Home from './pages/Home'; ReactDOM.render( <BrowserRouter> <Layout> <Routes> <Route path="/" element={<Home/>} /> </Routes> </Layout> </BrowserRouter>, document.getElementById('root') );
Создание статической домашней страницы Nordic Store
Мы почти завершили базовую настройку. Мы разделили шаблон Nordic Store на разделы Заголовок, Нижний колонтитул и Главная в вашем приложении.
src/components/Layout/Header/Header.js
import React from "react"; class Header extends React.Component { render() { return ( <header> <nav id="header" className="w-full z-30 top-0 py-1"> <div className="w-full container mx-auto flex flex-wrap items-center justify-between mt-0 px-6 py-3"> <label htmlFor="menu-toggle" className="cursor-pointer md:hidden block"> <svg className="fill-current text-gray-900" xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 20 20"> <title>menu</title> <path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z"></path> </svg> </label> <input className="hidden" type="checkbox" id="menu-toggle" /> <div className="hidden md:flex md:items-center md:w-auto w-full order-3 md:order-1" id="menu"> <nav> <ul className="md:flex items-center justify-between text-base text-gray-700 pt-4 md:pt-0"> <li><a className="inline-block no-underline hover:text-black hover:underline py-2 px-4" href="#">Shop</a></li> <li><a className="inline-block no-underline hover:text-black hover:underline py-2 px-4" href="#">About</a></li> </ul> </nav> </div> <div className="order-1 md:order-2"> <a className="flex items-center tracking-wide no-underline hover:no-underline font-bold text-gray-800 text-xl " href="#"> <svg className="fill-current text-gray-800 mr-2" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <path d="M5,22h14c1.103,0,2-0.897,2-2V9c0-0.553-0.447-1-1-1h-3V7c0-2.757-2.243-5-5-5S7,4.243,7,7v1H4C3.447,8,3,8.447,3,9v11 C3,21.103,3.897,22,5,22z M9,7c0-1.654,1.346-3,3-3s3,1.346,3,3v1H9V7z M5,10h2v2h2v-2h6v2h2v-2h2l0.002,10H5V10z" /> </svg> NORDICS </a> </div> <div className="order-2 md:order-3 flex items-center" id="nav-content"> <a className="inline-block no-underline hover:text-black" href="#"> <svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <circle fill="none" cx="12" cy="7" r="3" /> <path d="M12 2C9.243 2 7 4.243 7 7s2.243 5 5 5 5-2.243 5-5S14.757 2 12 2zM12 10c-1.654 0-3-1.346-3-3s1.346-3 3-3 3 1.346 3 3S13.654 10 12 10zM21 21v-1c0-3.859-3.141-7-7-7h-4c-3.86 0-7 3.141-7 7v1h2v-1c0-2.757 2.243-5 5-5h4c2.757 0 5 2.243 5 5v1H21z" /> </svg> </a> <a className="pl-3 inline-block no-underline hover:text-black" href="#"> <svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <path d="M21,7H7.462L5.91,3.586C5.748,3.229,5.392,3,5,3H2v2h2.356L9.09,15.414C9.252,15.771,9.608,16,10,16h8 c0.4,0,0.762-0.238,0.919-0.606l3-7c0.133-0.309,0.101-0.663-0.084-0.944C21.649,7.169,21.336,7,21,7z M17.341,14h-6.697L8.371,9 h11.112L17.341,14z" /> <circle cx="10.5" cy="18.5" r="1.5" /> <circle cx="17.5" cy="18.5" r="1.5" /> </svg> </a> </div> </div> </nav> </header> ); } } export default Header;
Не забудьте при копировании изменить class
на className
и for
на htmlFor
. Кроме того, игнорируйте действительные предупреждения href
warnings:
src/components/Layout/Footer/Footer.js
import React from "react"; class Footer extends React.Component { render() { return ( <footer className="container mx-auto bg-white py-8 border-t border-gray-400"> <div className="container flex px-3 py-8 "> <div className="w-full mx-auto flex flex-wrap"> <div className="flex w-full lg:w-1/2 "> <div className="px-3 md:px-0"> <h3 className="font-bold text-gray-900">About</h3> <p className="py-4"> Lorem ipsum dolor sit amet, consectetur adipiscing elit. Maecenas vel mi ut felis tempus commodo nec id erat. Suspendisse consectetur dapibus velit ut lacinia. </p> </div> </div> <div className="flex w-full lg:w-1/2 lg:justify-end lg:text-right"> <div className="px-3 md:px-0"> <h3 className="font-bold text-gray-900">Social</h3> <ul className="list-reset items-center pt-3"> <li> <a className="inline-block no-underline hover:text-black hover:underline py-1" href="#">Add social links</a> </li> </ul> </div> </div> </div> </div> </footer> ); } } export default Footer;
src/pages/Home.js
import React from 'react'; const products = [ { id: 1, name: 'Product Name', href: '#', price: '$9.99', imageSrc: 'https://images.unsplash.com/photo-1555982105-d25af4182e4e?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 2, name: 'Product Name', href: '#', price: '$10.99', imageSrc: 'https://images.unsplash.com/photo-1508423134147-addf71308178?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 3, name: 'Product Name', href: '#', price: '$12.99', imageSrc: 'https://images.unsplash.com/photo-1449247709967-d4461a6a6103?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 4, name: 'Product Name', href: '#', price: '$9.99', imageSrc: 'https://images.unsplash.com/reserve/LJIZlzHgQ7WPSh5KVTCB_Typewriter.jpg?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 5, name: 'Product Name', href: '#', price: '$6.99', imageSrc: 'https://images.unsplash.com/photo-1467949576168-6ce8e2df4e13?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 6, name: 'Product Name', href: '#', price: '$10.99', imageSrc: 'https://images.unsplash.com/photo-1544787219-7f47ccb76574?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 7, name: 'Product Name', href: '#', price: '$22.99', imageSrc: 'https://images.unsplash.com/photo-1550837368-6594235de85c?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=400&h=400&q=80', }, { id: 8, name: 'Product Name', href: '#', price: '$19.99', imageSrc: 'https://images.unsplash.com/photo-1551431009-a802eeec77b1?ixlib=rb-1.2.1&auto=format&fit=crop&w=400&h=400&q=80', }, ] class Home extends React.Component { render() { return ( <div> <section className="bg-white py-8"> <div className="container mx-auto flex items-center flex-wrap pt-4 pb-12"> <nav id="store" className="w-full z-30 top-0 px-6 py-1"> <div className="w-full container mx-auto flex flex-wrap items-center justify-between mt-0 px-2 py-3"> <a className="uppercase tracking-wide no-underline hover:no-underline font-bold text-gray-800 text-xl " href="#"> Store </a> <div className="flex items-center" id="store-nav-content"> <a className="pl-3 inline-block no-underline hover:text-black" href="#"> <svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <path d="M7 11H17V13H7zM4 7H20V9H4zM10 15H14V17H10z" /> </svg> </a> <a className="pl-3 inline-block no-underline hover:text-black" href="#"> <svg className="fill-current hover:text-black" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"> <path d="M10,18c1.846,0,3.543-0.635,4.897-1.688l4.396,4.396l1.414-1.414l-4.396-4.396C17.365,13.543,18,11.846,18,10 c0-4.411-3.589-8-8-8s-8,3.589-8,8S5.589,18,10,18z M10,4c3.309,0,6,2.691,6,6s-2.691,6-6,6s-6-2.691-6-6S6.691,4,10,4z" /> </svg> </a> </div> </div> </nav> <div className="grid grid-cols-1 gap-y-10 sm:grid-cols-2 gap-x-6 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8"> {products.map((product) => ( <a key={product.id} href={product.href}> <img className="hover:grow hover:shadow-lg" src={product.imageSrc} /> <div className="pt-3 flex items-center justify-between"> <p className="">{product.name}</p> <svg className="h-6 w-6 fill-current text-gray-500 hover:text-black" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M12,4.595c-1.104-1.006-2.512-1.558-3.996-1.558c-1.578,0-3.072,0.623-4.213,1.758c-2.353,2.363-2.352,6.059,0.002,8.412 l7.332,7.332c0.17,0.299,0.498,0.492,0.875,0.492c0.322,0,0.609-0.163,0.792-0.409l7.415-7.415 c2.354-2.354,2.354-6.049-0.002-8.416c-1.137-1.131-2.631-1.754-4.209-1.754C14.513,3.037,13.104,3.589,12,4.595z M18.791,6.205 c1.563,1.571,1.564,4.025,0.002,5.588L12,18.586l-6.793-6.793C3.645,10.23,3.646,7.776,5.205,6.209 c0.76-0.756,1.754-1.172,2.799-1.172s2.035,0.416,2.789,1.17l0.5,0.5c0.391,0.391,1.023,0.391,1.414,0l0.5-0.5 C14.719,4.698,17.281,4.702,18.791,6.205z" /> </svg> </div> <p className="pt-1 text-gray-900">{product.price}</p> </a> ))} </div> </div> </section> </div> ); } } export default Home;
Мы создали домашнюю страницу без карусели. Мы реализуем карусель в следующей главе.
Добавьте приведенный ниже стиль для мобильного меню.
src/index.css
@tailwind base; @tailwind components; @tailwind utilities; #menu-toggle:checked + #menu { display: block; }
Полный рабочий код этой главы выложен и доступен на Github — archive/Chapter_1.
Полная демонстрация:https://balajidharma.github.io/tailwindcss-nordic-store/
Далее: Глава 2. Пошаговое руководство по использованию RESTful API в React
На этом мы заканчиваем нашу первую главу. Спасибо за чтение.
Оставайтесь с нами, чтобы узнать больше!
Больше контента на plainenglish.io. Подпишитесь на нашу бесплатную еженедельную рассылку новостей. Получите эксклюзивный доступ к возможностям написания и советам в нашем сообществе Discord.