Создадим полноценный сайт с меню, слайдером, обратным отчетом и прочими обычными и не очень компонентами
Что мы будем строить?
Лучше один раз увидеть , чем 100 раз услышать.
Готовый сайт на surge.sh
Начнем, как обычно с создания проекта на основе create-react-app. Если вы еще не знакомы с новой версией, то вам сюда ==> Что нового в приложении Create React App 3, а если не получилось запустить обновленную, третью версию, то вам сюда ==> cra3-boilerplate. Возмите готовое, настроенное мной решение и пользуйтесь в удовольствие.
Запуск и настройку не рассказываю. Об этом я много писал ранее. Считаю, что вы уже развернули приложение в отдельной папке, запустили его и готовы приступить к работе.
В файле App.js оставляем только то, что будем использовать:
В resources положим и файл для стилизации всего приложения - style.css Все стили для нашего приложения мы поместим в папку
По поводу стилизации вашего приложения, я надеюсь, что на этом этапе вы можете сами написать нужные стили для вашего приложения и я на этом останавливаться не буду.
Итак. Мы будем использовать следующие модули:
Ядро:
И иконки:
Одной командой:
В файл App.js импортируем стили, которые создадим создадим в ранее созданном файле стилей и будем их добавлять к классам, которые мы будем присваивать нашим элементам разметки во всем приложении. Так можно поступить в данном случае, потому что у нас компонент App будет являться родителем для всего приложения. Само приложение будет небольшое, поэтому нет смысла использовать стороннюю библиотеку.
Все компоненты мы будем помещать в отдельной папке. Создадим её - Components в папке src. В ней разу создадим папку для компонента
И сразу импортируем и выведем его в App.js
Сейчас мы просто увидим слово Header на странице приложения.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Creating the main structure and connecting the header"
ci -m — здесь и далее - коммит.
Header.js
Помимо инлайновых стилей, добавил немного и в resources/style.css
Стили для шрифтов, я взял в Google Fonts и сразу же добавил их в header файла public/index.html В браузере пока что так:
В браузере так:
Пока что на клик ничего не происходит. Но мы сделаем так, что по клику будет открываться сайдбар с меню справа. Вы можете это легко сделать и сверху, и снизу и слева, самостоятельно.
Пока что мы просто добавим элементу
Если теперь посмотретьв браузере. то в консоли мы увидим "OPEN" при клике.
Идем в "Material-UI"==> "Component Demos"==> "Drawer". Здесь вы можете выбрать различные варианты для расположения сайтбара.
Оно определяется значение атрибута
Для сохранения порядка в нашем приложении, мы создадим в папке Header_Footer отдельный файл - SideDrawer.js
Внутри него определим обычный компонент без состояния (stateless component) и импортируем в него
Кстати, если вы используете VS-Code, то там есть отличный плагин - Reactjs code snippets, котоый позволяет писать компоненты одной короткой командой:
В open мы в пропсах передадим состояние,и функцию закрытия. Пока что подключим наш файл в Header.js и добавим функцию, которую будем передавать вниз. Добавим состояние, используя hook - useState. Проще показать:
Header.js
И доделаем SideDrawer.js
Теперь по клику на сандвич показывается сайдбар.
Добавим разделы меню:
SideDrawer.js
Стилизацию придает сама библиотека Material UI, в зависимости от заданных параметров листа и его итемов. Более подробно см в документации.
На клик в консоль, пока что просто вывел название элемента.
Теперь по клику мы сможем видеть наше меню, а в консоли будет пока что выводиться название раздела по которому кликнули.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Toggle Menu"
App
Теперь у нас появился скрол и мы можем видеть то, что наше меню остается фиксированным к верхнему краю и никак не изменяется при прокрутке вниз. Для лучшего отображения, добавили цвет странице.
Добавим меню прозрачности при позиции без скрола - то есть в самом верхнем положении.
Для этого идем в файл Header.js и нам нужно добавить "состояние" нашему компоненту, которое будет отвечать за прозрачность меню (показать или нет меню полностью).
Сделаем это с помощью хука
Там, гдде мы задавали с вами цвет компоненту
Сейчас все будет выглядеть так:
Уберем тень от меню -
Теперь наша задача изменить значение нашей переменной
Для этого нам нужно будет получить величину скрола. Это все просто, как в ванильном JS.
Эту конструкцию мы поместим внутри функции, которая будет находиться в хуке
Теперь создадим стрелочную функцию
Эту функцию можно записать еще короче, тернарным оператором, но я оставлю ее здесь так, для наглядности.В коде можно записать и так:
И даже скобки не нужны, но... Мне вообще нравится тенденция использования коротких записей, только там, где это действительно необходимо, а не там, где хочется разработчику. Красота чтения такого кода, как книги, превосходит затраты на пару килобайт, компилированног кода. Всегда есть "золотая середина" и ее стоит придерживаться!
Теперь в браузере мы получим такую картину:
Вся красота создания таких компонентов в том, что они не только легкие, но еще и могут быть использованы как модули в других проектах. Они имеют свои независимые "состояния" и могут использоваться многократно со стилизацией под каждый отдельный проект.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Transparent Menu on Scroll events"
По центру слайдера, мы создадим некий заголовок в двойной рамке. Слайдер будет сам запускаться и менять картинки непрерывно. Впрочем, вы сами сможете регулировать все его доступные функции, а их достаточно даже для требовательных разработчиков и пользователей.
В нижней части слайдера мы выведем калькулятор, который будет показывать оставшееся время (дни, часы, минуты, секунды) до намеченного события. Например - конференции React-разработчиков в Амстердаме.
Идем в проект и в папке Componentsи создадим там папку для нашего слайдера, заголовка и таймера - Sliderв ней файл index.js в который и будет собираться весь наш слайдер из трех вышеперечисленных компонентов.
Набираем - rsc и жмем Enter и у нас уже есть готовый функциональный компонент. переименовываем его в
Всему возвращаемому элементу -
Внутри него создадим два вложенных элемента в которых и будет находиться заголовок:
Импортируем все это в App.js и выводим на экран.
На экране покажется заголовок, который мы вывели, справа, просто черным текстом. Добавим немного стилей в файле
src/resources/style.css
Вы можете стилизовать все сами, как вам больше нравится.
Добавляем React-Slick
Прям там, на странице, мы возьмем cdn - ссылки для подключения css и добавим их в
Там же на странице есть хорошие примеры подключения и использования слайдера. Добавляем его в проект:
Думаю, что тут все и так понятно: dots - не показывать "точки" внизу слайдера, с бесконечной прокруткой, автоматический старт и задаем произвольно скорость.
Нашему оборачивающему диву добавим класс для стилизации и некоторые произвольные стили, которые я написал ниже.
src/resources/style.css
Добавим ему и инлайновые стили
Здесь самый интересный, это высота, которая рассчитывается динамически от высоты окна браузера. Именно благодаря этому наш слайдер будет всегда занимать полностью всю высоту любого экрана и второй компонент будет появляться только при скроле.
Если сейчас прописать инлайн этому элементу какой либо другой цвет (например: background:'red'), то мы наглядно в этом убедимся.
Идем далее и по образцу на странице библиотеки слайдера, создадим компонент
Приведу этот файл полностью для наглядности.
Carousel.js
Таким образом мы с вами получили слайдер, который сам запускается, занимает всю высоту экрана и меню, которое появляется только при начале скрола страницы.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Slider and Menu"
В компоненте Timer.js зададим общему диву класс для дальнейшей стилизации
Внутри него создадим еще один див с заголовком события. Сразу после него еще один див с классом
Внутри него будет див с классом
Timer.js
В браузере пока что это выглядит очень неприглядно:
Добавим стили:
src/resources/style.css
Теперь так:
Идем в файл Timer.js.Теперь мы продублируем див с классом - countdown_item для того, чтобы на страницу выводились не только дни, но и часы, минуты и секунды.
Пока что так.
Нам потребуется для этого - react-reveal
Отлично все написано на официальном сайте - react-reveal
Или на странице gitHub - github.com react-reveal
Согласно документации устанавливаем его.
Здесь есть github.com react-reveal - примеры, которые вы можете смело использовать в ваших приложениях:
Теперь импортируем его в файл:
И обернем в него все что возвращает наш компонент (внутри return
Таким образом у нас появился Fade эффект - плавного появления таймера справа.
Файл полностью:
Timer.js
Timer.js
Если посмотреть в браузер, то все "появляется и тикает". В итоге мы получили меню, которое меняется в зависимости от прокрутки, слайдер, который запускается автоматически и работает с определенным интервалом (кстати это не лишает возможности крутить его вручную мышкой), таймер, который плавно появляется при загрузке страницы и динамически отсчитывает время оставшееся до наступления события.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "TimerUntil event"
PS:
Иногда, бывают такие ситуации, что указывать
Как исправить? Стоит задать
Timer.js
Все что я добавил, выделено красным. Я думаю, что объяснять это не надо. С помощью библиотек, это можно было сделать проще и нагляднее, но мы решили идти по пути наименьшего использования сторонних ресурсов, поэтому так.
Все последние изменения вы можете посмотреть на gitHub react-site-slider-abc
ci -m "added dinamic deadline date"
Что мы будем строить?
Лучше один раз увидеть , чем 100 раз услышать.
Готовый сайт на surge.sh
Все статьи этого проекта:
- React-Сайт ( I ). Меню и слайдер.
- React-Сайт ( II ). Инфо-основная секция.
- React-Сайт ( III ). Цены-локация секции.
- React-Сайт ( IV ). Навигация по странице. Деплой приложения
Начнем, как обычно с создания проекта на основе create-react-app. Если вы еще не знакомы с новой версией, то вам сюда ==> Что нового в приложении Create React App 3, а если не получилось запустить обновленную, третью версию, то вам сюда ==> cra3-boilerplate. Возмите готовое, настроенное мной решение и пользуйтесь в удовольствие.
Запуск и настройку не рассказываю. Об этом я много писал ранее. Считаю, что вы уже развернули приложение в отдельной папке, запустили его и готовы приступить к работе.
Удаляем лишнее.
В папке src удаляем все кроме App.js index.js В файле index.js оставляем только то, что будем использовать:import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; ReactDOM.render(<App />, document.getElementById("root"));
В файле App.js оставляем только то, что будем использовать:
import React from "react"; function App() { return <div className="App"> My App </div>; } export default App;
Добавляем нужное.
Папки-файлы
В папке src мы создадим папку resources, а в не папку слайд-фото для нашего слайдера - img. Вы можете взять любые три изображения размером 1920px x 1200px и сразу поместить их в эту папку.В resources положим и файл для стилизации всего приложения - style.css Все стили для нашего приложения мы поместим в папку
Зависимости
Мы будем использовать Material-UI. Ранее я уже рассказывал о том. как использовать библиотеку Materialize. Позднее вы увидите. что они очень похожи и их использование не будет вызывать у вас беспокойства.По поводу стилизации вашего приложения, я надеюсь, что на этом этапе вы можете сами написать нужные стили для вашего приложения и я на этом останавливаться не буду.
Итак. Мы будем использовать следующие модули:
- @material-ui/core
- @material-ui/icons
- react-reveal
- react-scroll
- react-slick
Ядро:
// with npm
npm install @material-ui/core
// with yarn
yarn add @material-ui/core
npm install @material-ui/core
// with yarn
yarn add @material-ui/core
И иконки:
npm install @material-ui/icons
Одной командой:
npm install @material-ui/core @material-ui/icons
В файл App.js импортируем стили, которые создадим создадим в ранее созданном файле стилей и будем их добавлять к классам, которые мы будем присваивать нашим элементам разметки во всем приложении. Так можно поступить в данном случае, потому что у нас компонент App будет являться родителем для всего приложения. Само приложение будет небольшое, поэтому нет смысла использовать стороннюю библиотеку.
import './resources/styles.css';
Все компоненты мы будем помещать в отдельной папке. Создадим её - Components в папке src. В ней разу создадим папку для компонента
Header
с одноименным названием и в ней файл Header.js .
import React from "react"; const Header = () => { return <div> Header </div>; }; export default Header;
И сразу импортируем и выведем его в App.js
import React from "react"; import './resources/style.css'; import Header from "./Compomemts/Header_Footer/Header"; function App() { return ( <div className="App"> <Header /> </div> ); } export default App;
Сейчас мы просто увидим слово Header на странице приложения.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Creating the main structure and connecting the header"
ci -m — здесь и далее - коммит.
Создание меню
Вывод логотипа и заголовка.
Импортируем в файл Header.js все необходимые для этого компоненты и создадим простую структуру на основе Material-UI.Header.js
import React from "react"; import AppBar from "@material-ui/core/AppBar"; import Toolbar from "@material-ui/core/Toolbar"; import MenuIcon from "@material-ui/icons/Menu"; import IconButton from "@material-ui/core/IconButton"; const Header = () => { return ( <AppBar position="fixed" style={{ background: "#090050", padding: " 20px 0px" }} > <Toolbar> <div className="header_logo"> <div className="font_left header_logo_title">wmg</div> <div className="font_left header_logo_caption">React mitting</div> </div> </Toolbar> </AppBar> ); }; export default Header;
Помимо инлайновых стилей, добавил немного и в resources/style.css
body { padding:0; margin:0; font-family: 'Roboto', sans-serif; } .font_left { font-family: 'Righteous', cursive; } /* ===============>>> HEADER <<<================ */ header { padding:10px 0px; transition: all 300ms ease-in; } header .header_logo { flex-grow: 1; } header .header_logo_title { text-transform: uppercase; font-size: 40px; } header .header_logo_caption { text-transform: uppercase; }
Стили для шрифтов, я взял в Google Fonts и сразу же добавил их в header файла public/index.html В браузере пока что так:
Вывод значка сандвич меню.
Добавим вывод значка сандвич-меню в файл Header.js
import React from "react";
import AppBar from "@material-ui/core/AppBar";
import Toolbar from "@material-ui/core/Toolbar";
import MenuIcon from "@material-ui/icons/Menu";
import IconButton from "@material-ui/core/IconButton";
const Header = () => {
return (
<AppBar
position="fixed"
style={{
background: "#090050",
padding: " 20px 0px"
}}
>
<Toolbar>
<div className="header_logo">
<div className="font_left header_logo_title">wmg</div>
<div className="font_left header_logo_caption">React mitting</div>
</div>
<IconButton aria-label="Menu" color="inherit">
<MenuIcon />
</IconButton>
</Toolbar>
</AppBar>
);
};
export default Header;
В браузере так:
Пока что на клик ничего не происходит. Но мы сделаем так, что по клику будет открываться сайдбар с меню справа. Вы можете это легко сделать и сверху, и снизу и слева, самостоятельно.
Пока что мы просто добавим элементу
<IconButton aria-label="Menu" color="inherit" onClick={() => console.log("OPEN")} >
Если теперь посмотретьв браузере. то в консоли мы увидим "OPEN" при клике.
Идем в "Material-UI"==> "Component Demos"==> "Drawer". Здесь вы можете выбрать различные варианты для расположения сайтбара.
Оно определяется значение атрибута
anchor="top"
компонента Drawer
. Атрибут open={this.state.top}
получает значение из состояния компонента. Функция изменяет его и от того, true / false
определяется показывать или нет меню-сайдбар.
Для сохранения порядка в нашем приложении, мы создадим в папке Header_Footer отдельный файл - SideDrawer.js
Внутри него определим обычный компонент без состояния (stateless component) и импортируем в него
Driwer
из Material-UI. Сразу же импортируем компонент List
и ListItem
оттуда же. Они нам потребуются для создания самого сайдбара с элементами.
Кстати, если вы используете VS-Code, то там есть отличный плагин - Reactjs code snippets, котоый позволяет писать компоненты одной короткой командой:
rcc
- React Class Componentrsc
- React Stateless Component
props
import React from 'react'; import Drawer from "@material-ui/core/Drawer"; import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; const SideDrawer = () => { return ( <Drawer anhor="right" open={} onClose={()=>{}} > Drawer </Drawer> ); }; export default SideDrawer;
В open мы в пропсах передадим состояние,и функцию закрытия. Пока что подключим наш файл в Header.js и добавим функцию, которую будем передавать вниз. Добавим состояние, используя hook - useState. Проще показать:
Header.js
import React, { useState } from "react"; import AppBar from "@material-ui/core/AppBar"; import Toolbar from "@material-ui/core/Toolbar"; import MenuIcon from "@material-ui/icons/Menu"; import IconButton from "@material-ui/core/IconButton"; import SideDrawer from "./SideDrawer"; const Header = () => { const [drawerOpen, setDrawerOpen] = useState(false); const toggleDrawer = value => { setDrawerOpen(value); }; return ( <AppBar position="fixed" style={{ background: "#090050", padding: " 20px 0px" }} > <Toolbar> <div className="header_logo"> <div className="font_left header_logo_title">wmg</div> <div className="font_left header_logo_caption">React mitting</div> </div> <IconButton aria-label="Menu" color="inherit" onClick={() => toggleDrawer(true)} > <MenuIcon /> </IconButton> <SideDrawer open={drawerOpen} onClose={value => toggleDrawer(value)} /> </Toolbar> </AppBar> ); }; export default Header;
И доделаем SideDrawer.js
import React from "react"; import Drawer from "@material-ui/core/Drawer"; import List from "@material-ui/core/List"; import ListItem from "@material-ui/core/ListItem"; const SideDrawer = props => { return ( <Drawer anchor="right" open={props.open} onClose={() => props.onClose(false)} > Drawer </Drawer> ); }; export default SideDrawer;
Теперь по клику на сандвич показывается сайдбар.
Добавим разделы меню:
SideDrawer.js
import React from "react";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
const SideDrawer = props => {
return (
<Drawer
anchor="right"
open={props.open}
onClose={() => props.onClose(false)}
>
<List component="nav">
<ListItem button onClick={() => console.log("Start Events")}>
Event starts in
</ListItem>
<ListItem button onClick={() => console.log("React info")}>
React info
</ListItem>
<ListItem button onClick={() => console.log(" Our Team")}>
Our Team
</ListItem>
<ListItem button onClick={() => console.log("Pricing")}>
Pricing
</ListItem>
<ListItem button onClick={() => console.log("Location")}>
Location
</ListItem>
</List>
</Drawer>
);
};
export default SideDrawer;
Стилизацию придает сама библиотека Material UI, в зависимости от заданных параметров листа и его итемов. Более подробно см в документации.
На клик в консоль, пока что просто вывел название элемента.
Теперь по клику мы сможем видеть наше меню, а в консоли будет пока что выводиться название раздела по которому кликнули.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Toggle Menu"
Добавление интерактивности меню.
Можно сделать так. что при открытии страницы меню будет иметь прозрачность, а при скроле, оно будет проявляться и находиться в фиксированном состоянии, прижатое к верхнему краю. Вначале нам нужно задать большую высоту странице, чтобы получить скрол. Для этого в компоненте App добавим инлайн стиль для всего компонента:App
import React from "react";
import "./resources/style.css";
import Header from "./Compomemts/Header_Footer/Header";
function App() {
return (
<div className="App" style={{ height: "2000px", background: "#BEE0FF" }}>
<Header />
</div>
);
}
export default App;
Теперь у нас появился скрол и мы можем видеть то, что наше меню остается фиксированным к верхнему краю и никак не изменяется при прокрутке вниз. Для лучшего отображения, добавили цвет странице.
Добавим меню прозрачности при позиции без скрола - то есть в самом верхнем положении.
Для этого идем в файл Header.js и нам нужно добавить "состояние" нашему компоненту, которое будет отвечать за прозрачность меню (показать или нет меню полностью).
Сделаем это с помощью хука
useState
и зададим начальное состояние - false
const [headerShow, setHeaderShow] = useState(false);
Там, гдде мы задавали с вами цвет компоненту
AppBar
, внутри метода render()
, мы добавим изменение цвета компонента по условию:
background: headerShow ? "#090050" : "transparent"
Сейчас все будет выглядеть так:
Уберем тень от меню -
boxShadow: 'none'
Теперь наша задача изменить значение нашей переменной
headerShow
на true
при скроле. Для этого мы будем использовать useEffect
хук, который позволяет нам заменять жизненые циклы в компонентах без состояния.
Для этого нам нужно будет получить величину скрола. Это все просто, как в ванильном JS.
window.addEventLestener('scroll', handleScroll)
Эту конструкцию мы поместим внутри функции, которая будет находиться в хуке
useEffect
, и для того, чтобы этот хук отслеживал только изменение переменной headerShow
, мы передадим ее хуку вторым аргументом в виде массива. Это не будет создавать нагрузку на приложение, потому что хук будет вызываться только при изменении этой переменной "состояния".
Теперь создадим стрелочную функцию
handleScroll
в которой будем изменять значение этого "состояния" в зависимости от данных скрола.
useEffect(() => { window.addEventListener("scroll", handleScroll); }, [headerShow]); const handleScroll = () =>{ if (window.scrollY > 0) { setHeaderShow(true) } else { setHeaderShow(false) } }
Эту функцию можно записать еще короче, тернарным оператором, но я оставлю ее здесь так, для наглядности.В коде можно записать и так:
const handleScroll = () =>{ (window.scrollY > 0) ? setHeaderShow(true) : setHeaderShow(false); }
И даже скобки не нужны, но... Мне вообще нравится тенденция использования коротких записей, только там, где это действительно необходимо, а не там, где хочется разработчику. Красота чтения такого кода, как книги, превосходит затраты на пару килобайт, компилированног кода. Всегда есть "золотая середина" и ее стоит придерживаться!
Теперь в браузере мы получим такую картину:
Вся красота создания таких компонентов в том, что они не только легкие, но еще и могут быть использованы как модули в других проектах. Они имеют свои независимые "состояния" и могут использоваться многократно со стилизацией под каждый отдельный проект.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Transparent Menu on Scroll events"
Слайдер
Переходим к слайдеру. В папке ресурсов, как мы и договорились ранее, есть папка с изображениями - img. все изображения имеют размер 1920 X 1200 px. Это позволит нам создавать слайдер на всю ширину окна браузера, без потери качества, в большинстве случаев.По центру слайдера, мы создадим некий заголовок в двойной рамке. Слайдер будет сам запускаться и менять картинки непрерывно. Впрочем, вы сами сможете регулировать все его доступные функции, а их достаточно даже для требовательных разработчиков и пользователей.
В нижней части слайдера мы выведем калькулятор, который будет показывать оставшееся время (дни, часы, минуты, секунды) до намеченного события. Например - конференции React-разработчиков в Амстердаме.
Идем в проект и в папке Componentsи создадим там папку для нашего слайдера, заголовка и таймера - Sliderв ней файл index.js в который и будет собираться весь наш слайдер из трех вышеперечисленных компонентов.
Набираем - rsc и жмем Enter и у нас уже есть готовый функциональный компонент. переименовываем его в
Slider
. Не забываем изменить имя и в экспорте!
Всему возвращаемому элементу -
div
добавим стиль div style={{position:'relative'}}
Внутри него создадим два вложенных элемента в которых и будет находиться заголовок:
import React from "react"; const Slider = () => { return ( <div style={{ position: "relative" }}> <div className="event_name"> <div className="wrapper">React Meetting</div> </div> </div> ); }; export default Slider;
Импортируем все это в App.js и выводим на экран.
import React from "react"; import "./resources/style.css"; import Header from "./Compomemts/Header_Footer/Header"; import Slider from "./Compomemts/Slider"; function App() { return ( <div className="App" style={{ height: "2000px", background: "#BEE0FF" }}> <Header /> <Slider /> </div> ); } export default App;
На экране покажется заголовок, который мы вывели, справа, просто черным текстом. Добавим немного стилей в файле
src/resources/style.css
/* =================>>> SLIDER <<<================== */ .event_name { position: absolute; top: 50%; left: 50%; width: 400px; height: 160px; -webkit-transform: translate(-50%, -50%); transform: translate(-50%, -50%); border: 2px solid white; } .event_name .wrapper { border: 2px solid white; height: 121px; margin: 6px; text-align: center; color: #fff; font-size: 40px; padding: 21px 70px 0px 70px; text-transform: uppercase; }
Вы можете стилизовать все сами, как вам больше нравится.
Добавляем React-Slick
Прям там, на странице, мы возьмем cdn - ссылки для подключения css и добавим их в
header
нашего html - файла public/index.html
Там же на странице есть хорошие примеры подключения и использования слайдера. Добавляем его в проект:
npm install react-slick --save
Внутри папки Slider создадим файл Carousel.js, там так же создаем компонент без состояния.
Импортируем сам слайдер
import Slider from "react-slick";
В индексовый файл слайдера импортируем карусель:
import Carousel from './Carousel';
И выводим ее на страницу перед заголовком.
Возвращаемся в компонент Carousel и внутри компонента создадим константу с настройками слайдера.
const settings = { dots: false, infinite:true, autoplay: true, speed: 500 }
Думаю, что тут все и так понятно: dots - не показывать "точки" внизу слайдера, с бесконечной прокруткой, автоматический старт и задаем произвольно скорость.
Нашему оборачивающему диву добавим класс для стилизации и некоторые произвольные стили, которые я написал ниже.
src/resources/style.css
.carrousel_wrapper { height:700px; overflow: hidden; } .carrousel_image { background-size: cover !important; }
Добавим ему и инлайновые стили
style={{ height:`${window.innerHeight}px`, overflow:'hidden' }}
Здесь самый интересный, это высота, которая рассчитывается динамически от высоты окна браузера. Именно благодаря этому наш слайдер будет всегда занимать полностью всю высоту любого экрана и второй компонент будет появляться только при скроле.
Если сейчас прописать инлайн этому элементу какой либо другой цвет (например: background:'red'), то мы наглядно в этом убедимся.
Идем далее и по образцу на странице библиотеки слайдера, создадим компонент
Slider
внутри которого получим с помощью оператора rest - ...
все настройки ...settings
, как если бы мы их передали по отдельности так ( Slider dots: false infinite: true и т.д). Внутри него разместим наши слайды, которые импортируем в этот файл по отдельности из папки img. зададим им динамически высоту. А сами фото пойдут как фон дива. все очень очень просто!
Приведу этот файл полностью для наглядности.
Carousel.js
import React from "react"; import Slider from "react-slick"; import slide_one from "../../resources/img/slide_one.jpg"; import slide_two from "../../resources/img/slide_two.jpg"; import slide_three from "../../resources/img/slide_three.jpg"; const Carousel = () => { const settings = { dots: false, infinite: true, autoplay: true, speed: 500 }; return ( <div className="carrousel_wrapper" style={{ height: `${window.innerHeight}px`, overflow: "hidden" }} > <Slider {...settings}> <div> <div className="carrousel_image" style={{ background: `url(${slide_one})`, height: `${window.innerHeight}px` }} /> </div> <div> <div className="carrousel_image" style={{ background: `url(${slide_two})`, height: `${window.innerHeight}px` }} /> </div> <div> <div className="carrousel_image" style={{ background: `url(${slide_three})`, height: `${window.innerHeight}px` }} /> </div> </Slider> </div> ); }; export default Carousel;
Таким образом мы с вами получили слайдер, который сам запускается, занимает всю высоту экрана и меню, которое появляется только при начале скрола страницы.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "Slider and Menu"
Обратный отсчет
Создаем сам таймер
Начнем с того, что в папке Slider создадим для этого компонента отдельный файл Timer.js c rsc (react stateless component). Сразу же импортируем его в Slider/index.js и выведем его сразу перед закрывающим последним дивом.В компоненте Timer.js зададим общему диву класс для дальнейшей стилизации
className="countdown_wrapper"
Внутри него будут секции с днями, часами, минутами и секундами.
Внутри него создадим еще один див с заголовком события. Сразу после него еще один див с классом
countdown_bottom
и уже внутри него у нас будут 4 разных значения для вывода цифр.
Внутри него будет див с классом
countdown_item
, в который мы поместим еще два дива, один из которых будет для вывода значений - countdown_time
, второй для вывода названия значения - countdown_tag
.
Timer.js
import React from "react"; const Timer = () => { return ( <div className="countdown_wrapper"> <div className="countdown_top">Event starts in</div> <div className="countdown_bottom"> <div className="countdown_item"> <div className="countdown_time">15</div> <div className="countdown_tag">Days</div> </div> </div> </div> ); }; export default Timer;
В браузере пока что это выглядит очень неприглядно:
Добавим стили:
src/resources/style.css
/* =====================>>> TIMER <<<======================== */ .countdown_wrapper { position:absolute; bottom: 0px; color:#ffffff; } .countdown_wrapper .countdown_top { background: #ff4800; font-size: 19px; padding: 10px; display: inline-block; text-transform: uppercase; } .countdown_wrapper .countdown_bottom { display: flex; background: red; padding: 10px 20px; } .countdown_wrapper .countdown_time { font-size: 70px; border-right: 1px solid red; margin-right: 14px; padding-right: 49px; } .countdown_wrapper .countdown_item:last-child .countdown_time{ border:none; } .countdown_wrapper .countdown_tag { text-transform: uppercase; font-size: 20px; padding-left: 7px; }
Теперь так:
Идем в файл Timer.js.Теперь мы продублируем див с классом - countdown_item для того, чтобы на страницу выводились не только дни, но и часы, минуты и секунды.
Пока что так.
Добавляем эффект появления
Теперь мы добавим эффект появления нашего таймера при перезагрузке страницы.Нам потребуется для этого - react-reveal
Отлично все написано на официальном сайте - react-reveal
Или на странице gitHub - github.com react-reveal
Согласно документации устанавливаем его.
npm install react-reveal --save
Здесь есть github.com react-reveal - примеры, которые вы можете смело использовать в ваших приложениях:
Теперь импортируем его в файл:
import Slide from 'react-reveal/Slide';
И обернем в него все что возвращает наш компонент (внутри return
()
). Зададим ему параметры left delay={1000}
Таким образом у нас появился Fade эффект - плавного появления таймера справа.
Файл полностью:
Timer.js
import React from "react"; import Slide from "react-reveal/Slide"; const Timer = () => { return ( <Slide left delay={1000}> <div className="countdown_wrapper"> <div className="countdown_top">Event starts in</div> <div className="countdown_bottom"> <div className="countdown_item"> <div className="countdown_time">15</div> <div className="countdown_tag">Days</div> </div> <div className="countdown_item"> <div className="countdown_time">15</div> <div className="countdown_tag">Hs</div> </div> <div className="countdown_item"> <div className="countdown_time">15</div> <div className="countdown_tag">Min</div> </div> <div className="countdown_item"> <div className="countdown_time">15</div> <div className="countdown_tag">Sec</div> </div> </div> </div> </Slide> ); }; export default Timer;
Добавляем логику (динамическое изменение значений)
Мы создадим эту часть таким образом, чтобы в "состояния" (хуком) сохранить некую дату события и значения Дни, часы, минуты, секунды. Затем мы создадим функцию, которая будет считать сколько осталось дней, часов, минут, секунд до этой даты и эти значения заносила в наши "переменные состояния". Эту функцию мы будем вызывать каждую секунду, после загрузки нашего приложения, при помощиsetInterval
, а полученные значения мы будем передавать в компонент, где и отобразим их на странице.
Это проще показать в коде.
Timer.js
import React, {useState, useEffect} from "react"; import Slide from "react-reveal/Slide"; const Timer = () => { const deadline = 'Dec, 16, 2019'; const [days, setDays] = useState('0'); const [hours , setHours] = useState('0'); const [minutes, setMinutes] = useState('0'); const [seconds, setSeconds] = useState('0'); const getTimeUntil = (deadline) =>{ const time = Date.parse(deadline) - Date.parse(new Date()); if(time < 0) { console.log('Date passed') } else { const seconds = Math.floor((time/1000)%60); const minutes = Math.floor((time/1000/60)%60); const hours = Math.floor((time/(1000*60*60))%24); const days = Math.floor(time/(1000*60*60*24)); setDays(days); setHours(hours); setMinutes(minutes); setSeconds(seconds); } } useEffect(()=>{ setInterval(()=> getTimeUntil(deadline),1000) },[seconds]) return ( <Slide left delay={1000}> <div className="countdown_wrapper"> <div className="countdown_top">Event starts in</div> <div className="countdown_bottom"> <div className="countdown_item"> <div className="countdown_time">{days}</div> <div className="countdown_tag">Days</div> </div> <div className="countdown_item"> <div className="countdown_time">{hours}</div> <div className="countdown_tag">Hs</div> </div> <div className="countdown_item"> <div className="countdown_time">{minutes}</div> <div className="countdown_tag">Min</div> </div> <div className="countdown_item"> <div className="countdown_time">{seconds}</div> <div className="countdown_tag">Sec</div> </div> </div> </div> </Slide> ); }; export default Timer;
Если посмотреть в браузер, то все "появляется и тикает". В итоге мы получили меню, которое меняется в зависимости от прокрутки, слайдер, который запускается автоматически и работает с определенным интервалом (кстати это не лишает возможности крутить его вручную мышкой), таймер, который плавно появляется при загрузке страницы и динамически отсчитывает время оставшееся до наступления события.
Все файлы проекта на этом этапе смотрите в репо - react-site-slider-abc
ci -m "TimerUntil event"
PS:
Иногда, бывают такие ситуации, что указывать
deadline
статически (присвоить постоянное значение) это не очень удобно. Я столкнулся с этим разместив этот учебный макет на surge. Время, в конце концов истекло и на сайте появились унылые нули.
Как исправить? Стоит задать
deadline
динамически, ну например, прибавлять к сегодняшней дате несколько дней. Я решил эту задачу очень просто - получил текущую дату, назначил новую и потом получил все данные новой даты deadline
в нужном формате
Timer.js
import React, { useState, useEffect } from "react";
import Slide from "react-reveal/Slide";
const Timer = () => {
let deadline = getDeadline();
function getDeadline() {
var D = new Date();
D.setDate(D.getDate() + 50);
var month = D.getMonth();
function LitMonth(month) {
switch (month) {
case 0:
month = "Jan";
break;
case 1:
month = "Feb";
break;
case 2:
month = "Mar";
break;
case 3:
month = "Apr";
break;
case 4:
month = "May";
break;
case 5:
month = "Jun";
break;
case 6:
month = "Jul";
break;
case 7:
month = "Aug";
break;
case 8:
month = "Sep";
break;
case 9:
month = "Oct";
break;
case 10:
month = "Nov";
break;
case 11:
month = "Dec";
break;
default:
}
return month;
}
month = LitMonth(month);
var day = D.getDate();
var year = D.getFullYear();
D = month + " " + day + " " + year;
return D;
}
const [days, setDays] = useState("0");
const [hours, setHours] = useState("0");
const [minutes, setMinutes] = useState("0");
const [seconds, setSeconds] = useState("0");
const getTimeUntil = (deadline) => {
const time = Date.parse(deadline) - Date.parse(new Date());
if (time < 0) {
console.log("Date passed");
} else {
const seconds = Math.floor((time / 1000) % 60);
const minutes = Math.floor((time / 1000 / 60) % 60);
const hours = Math.floor((time / (1000 * 60 * 60)) % 24);
const days = Math.floor(time / (1000 * 60 * 60 * 24));
setDays(days);
setHours(hours);
setMinutes(minutes);
setSeconds(seconds);
}
};
useEffect(() => {
setInterval(() => getTimeUntil(deadline), 1000);
}, [seconds]);
return (
<Slide left delay={1000}>
<div className="countdown_wrapper">
<div className="countdown_top">Event starts in</div>
<div className="countdown_bottom">
<div className="countdown_item">
<div className="countdown_time">{days}</div>
<div className="countdown_tag">Days</div>
</div>
<div className="countdown_item">
<div className="countdown_time">{hours}</div>
<div className="countdown_tag">Hs</div>
</div>
<div className="countdown_item">
<div className="countdown_time">{minutes}</div>
<div className="countdown_tag">Min</div>
</div>
<div className="countdown_item">
<div className="countdown_time">{seconds}</div>
<div className="countdown_tag">Sec</div>
</div>
</div>
</div>
</Slide>
);
};
export default Timer;
Все что я добавил, выделено красным. Я думаю, что объяснять это не надо. С помощью библиотек, это можно было сделать проще и нагляднее, но мы решили идти по пути наименьшего использования сторонних ресурсов, поэтому так.
Все последние изменения вы можете посмотреть на gitHub react-site-slider-abc
ci -m "added dinamic deadline date"
React-Сайт ( I ). Меню И Слайдер. >>>>> Download Now
ОтветитьУдалить>>>>> Download Full
React-Сайт ( I ). Меню И Слайдер. >>>>> Download LINK
>>>>> Download Now
React-Сайт ( I ). Меню И Слайдер. >>>>> Download Full
>>>>> Download LINK