В этой части сделаем две очень важные секции - секция вывода цены и локации.
Все статьи этого проекта:
Задачу разделим на два этапа. На первом этапе создадим секцию цен. Это довольно простая задача, но есть одно но.
Если посмотреть на картинку, то все выглядит довольно просто. У нас есть три блока, которые находятся внутри секции. Каждый блок имеет свои значения цены, описания, позиции и главное, то чего вы не видите на статической картинке -
нам нужно выводить блоки с последовательным проявлением. Вначале должен показаться блок. который по центру и после задержки в пол сек. уже первый и третий блоки.
Кнопки, мы уже создали отдельный компонент
MyButton
в который мы передадим нужные свойства. Это можно во внимание уже не брать.
Задачу можно решить разными путями. Я решил все это создать в одном компоненте. Данные можно передать в этот компонент извне, но так как мы можем их сохранять в самом компоненте. то это еще одно упрощение задачи. Данные можно сохранить в виде отдельных массивов (массив - цен, описаний, и пр.), тогда мы сможем их выводить в нужном порядке используя индекс в одном переборе (
map()
) и по индексу выводить значения из других массивов. Например так:
const arr_1 = ['Price-1', 'Price-2', 'Price-3'];
const arr_2 = ['Description-1', 'Description-2', 'Description-3'];
const arr_3 = ['Something-1','Something-2','Something-3'];
function iter(arr_1, arr_2, arr_3){
arr_1.map((item, index)=>(console.log("Price = "+ arr_1[index] + "; Description = " + arr_2[index] + "; Something = " + arr_3[index] + "Index = " + "; Index = " + index)))
}
iter(arr_1, arr_2, arr_3);
// Price = Price-1; Description = Description-1; Something = Something-1Index = ; Index = 0
// Price = Price-2; Description = Description-2; Something = Something-2Index = ; Index = 1
// Price = Price-3; Description = Description-3; Something = Something-3Index = ; Index = 2
В данном случае способ вывода в консоль значения не имеет. Главное что омы получаем таким образом доступ к нужным данным, которые все равно, мы будем выводить в
jsx
.
Второй вариант - это (обычный) сделать один массив данным с отдельными объектами - в виде каждого блока. У каждого объекта будут ключи - поля (name, price, description, position, link, delay). Вы можете выбрать любой вариант,который вам больше нравится. Главное. что в любом случае у нас будет возможность задать нужную задержку выполнения появления блока -
delay
и применить ее к нужному блоку.
Способ хранения данных (внутри отдельного компонента или во внешнем файле) для нас сейчас значения не имеет, но стоит обратить внимание на то как вы храните эти значения. Я встречал сохранение статических данных в
state
компонента. Считаю это излишним, потому что в стейтах есть смысл хранить изменяемые значения, а не статические, как в данном случае. Это облегчит создание самих компонентов, ускорит их работу и избавит от проблем отладки в будущем. Хватит слов. К коду.
Создадим отдельную папку и индексовый файл для нашего компонента в папке компонентов. Как мы и договорились, это будет компонент без состояния. Сразу же подключим и выведем его в файле
App.js
import Pricing from './Compomemts/Pricing';
<Pricing />
Для
Components/Pricing/index.js
import React from "react";
const Pricing = () => {
return (
<div className="bck_black">
<div className="center_wrapper pricing_section">
<h2>Pricing</h2>
<div className="pricing_wrapper">Some text</div>
</div>
</div>
);
};
export default Pricing;
Убедились, что все работает. Слева внизу появится в браузере слово - Pricing.
Теперь внутри нашего компонента создадим общую разметку для вывода трех блоков - выше в коде красным.
Добавляем слили
recourses/style.css
/* ====================>>> PRICING <<<=================================== */
.pricing_section {
padding: 70px 0px;
}
.pricing_section h2 {
color: #ffffff;
text-transform: uppercase;
text-align: center;
font-size: 50px;
margin: 0;
}
.pricing_wrapper {
display: flex;
flex-wrap: wrap;
}
.pricing_wrapper .pricing_item{
flex-grow: 1;
width: 33%;
padding: 20px;
box-sizing: border-box;
}
.pricing_wrapper .pricing_inner_wrapper {
border:2px solid #ffa800;
padding: 50px 20px;
}
.pricing_inner_wrapper .pricing_title {
color: #ffffff;
text-align: center;
border-bottom: 1px solid #ffa800;
padding-bottom: 20px;
}
.pricing_inner_wrapper .pricing_title span:nth-child(1) {
font-size: 50px;
display: block;
}
.pricing_inner_wrapper .pricing_title span:nth-child(2) {
text-transform: uppercase;
font-size: 28px;
font-weight: 300;
}
.pricing_inner_wrapper .pricing_description {
color: #b8b8b8;
font-weight: 300;
font-size: 14px;
text-align: center;
padding: 20px 0px;
min-height: 70px;
}
.pricing_inner_wrapper .pricing_buttons {
text-align: center;
}
После этого в браузере мы увидим наше слово выеденное один раз.
Данные я решил собрать вместе в массив объектов и разместил их внутри компонента. Все данные произвольные, кроме
data.delay
, значения которым мы дали согласно тому в какой последовательности блоки будут выводиться на экран.
Components/Pricing/index.js
const data = [
{
prices: 100,
positions: "Balcony",
desc:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt uts",
linkto: "https://twitter.com/JroslavK",
delay: 500
},
{
prices: 150,
positions: "Medium",
desc:
"Dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea",
linkto:
"https://www.facebook.com/Yaroslav-Web-Master-1446556072148794/?modal=admin_todo_tour",
delay: 0
},
{
prices: 250,
positions: "Star",
desc:
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
linkto:
"https://www.facebook.com/groups/1786288918273718/?ref=bookmarks",
delay: 500
}
];
Импортируем в этот файл кнопку
MyButton
, которую мы создали в прошлом посте.
import MyButton from '../Utils/myButton';
Сразу же импортируем и Zoom эффект из react-reveal
import Zoom from "react-reveal/Zoom";
В этот компонент -
Zoom
мы будем оборачивать наши компоненты в цикле и передавать им задержку показа на странице -
datadelay
каждого компонента отдельно.
Там где у нас сейчас выводится слово Some thing, мы будем выводить функцию, которая будет перебирать наши данные (методом
map
) и вернет разметку в которую поместит соответствующие данные каждого блока.
Функцию привожу ниже. В ней нет ничего необычного. Все как всегда. перебираем данные и выводим в нужных местах разметки.
Components/Pricing/index.js
const showBoxes = () =≶
data.map((item, i) =≶ (
<Zoom delay={item.delay} key={i}≶
<div className="pricing_item"≶
<div className="pricing_inner_wrapper"≶
<div className="pricing_title"≶
<span≶${item.prices}</span≶
<span≶{item.positions}</span≶
</div≶
<div className="pricing_description"≶{item.desc}</div≶
<div className="pricing_buttons"≶
<MyButton
text="Purchase"
bck="#ffa800"
color="#ffffff"
link={item.linkto}
/≶
</div≶
</div≶
</div≶
</Zoom≶
));
Для того, чтобы все нормально отобразилось на странице, мы вместо вывода слова Some thing сделаем вызов нашей функции.
<div className="pricing_wrapper">{showBoxes()}</div>
Теперь как только компонент загрузится, вызовется функция, которая вернет нам готовую разметку для каждого из трех блоков, уже с соответствующими данными.
Components/Pricing/index.js полностью
import React from "react";
import Zoom from "react-reveal/Zoom";
import MyButton from "../Utils/myButton";
const Pricing = () => {
const data = [
{
prices: 100,
positions: "Balcony",
desc:
"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt uts",
linkto: "https://twitter.com/JroslavK",
delay: 500
},
{
prices: 150,
positions: "Medium",
desc:
"Dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea",
linkto:
"https://www.facebook.com/Yaroslav-Web-Master-1446556072148794/?modal=admin_todo_tour",
delay: 0
},
{
prices: 250,
positions: "Star",
desc:
"Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.",
linkto: "https://www.facebook.com/groups/1786288918273718/?ref=bookmarks",
delay: 500
}
];
const showBoxes = () =>
data.map((item, i) => (
<Zoom delay={item.delay} key={i}>
<div className="pricing_item">
<div className="pricing_inner_wrapper">
<div className="pricing_title">
<span>${item.prices}</span>
<span>{item.positions}</span>
</div>
<div className="pricing_description">{item.desc}</div>
<div className="pricing_buttons">
<MyButton
text="Purchase"
bck="#ffa800"
color="#ffffff"
link={item.linkto}
/>
</div>
</div>
</div>
</Zoom>
));
return (
<div className="bck_black">
<div className="center_wrapper pricing_section">
<h2>Pricing</h2>
<div className="pricing_wrapper">{showBoxes()}</div>
</div>
</div>
);
};
export default Pricing;
Если посмотреть в браузере, то можно увидеть, что получилось именно то, что и хотели.
Блоки выводятся в нужной последовательности.
Да.Прошу прощения. Я по невнимательности опустил опечатку в файле
Itils/MyButton.js, там в свойствах кнопки, должно быть конечно
size="small"
. После того, как все исправил, я убедился что ошибок в консоли нет.
Все файлы проекта на этом этапе смотрите в репо -
react-site-slider-abc
ci -m "Pricing section"
Локация
Цель - вывести секцию, которая займет 100% ширины и на которой будет показана гугл-карта с местонахождением события.
Здесь все проще, чем вы могли бы подумать. В папке компонентов для этого создадим отдельную папку
Location с индексовым файлом -
index.js и с обычным кодом для компонента без состояния:
src/Components/Location/index.js
import React from "react";
const Location = () => {
return (
<div >
// Здесь будет вся разметка
</div>
)
};
export default Location;
Добавим классы, для разметки.
Основной див у нас поучит
className="location_wrapper"
, а внутри него создадим отдельный див, для вывода наименования секции -
className="location_tag"
Сразу добавим стили:
resources/style.css
.location_wrapper {
position:relative;
}
.location_tag {
position: absolute;
bottom: 0px;
width: 100%;
}
.location_tag div{
background: #2c2c2c;
color: #ffffff;
text-transform: uppercase;
width: 220px;
margin: 0 auto;
font-size: 29px;
padding: 15px 20px;
text-align: center;
}
Далее идем в Гугл карты и находим нужный нам регион и объект.
Наша задача получить код для фрейма, который мы и выведем в компоненте реакт.
Вводим адрес. В моем случае это будет Amsterdam, Gedempt Hamerkanaal 231, De Kromhouthal. Нажимаем поделится - Share
В другом окне выбираем "встроенная карта" - Embeded Map
Убеждаемся, что у нас то, что надо показано на малом фрейме и берем нужный код - любым способом его копируем.
Возвращаемся в наше приложение и вставляем то, что скопировали сразу под основным дивом.
Теперь немного его доработаем. например изменим
allowfullscreen
на
allowFullScreen
добавим ширину 100% и высоту 500px. Да и важно. Теперь нам нужно отдельно добавить
title
, название выберете самостоятельно любое. Я написал просто
location
. Свойство
frameborder="0"
удалим совсем.
src/Components/Location/index.js полностью
import React from "react";
const Location = () => {
return (
<div className="location_wrapper">
<iframe
src="https://www.google.com/maps/embed?pb=!1m18!1m12!1m3!1d2435.290628985655!2d4.918337915802386!3d52.383281579788566!2m3!1f0!2f0!3f0!3m2!1i1024!2i768!4f13.1!3m3!1m2!1s0x47c609abb3be496b%3A0x1a140c53c426f7c7!2sthe+Kromhouthal!5e0!3m2!1sen!2sua!4v1559491565118!5m2!1sen!2sua"
width="100%"
height="500px"
allowFullScreen
title="location"
/>
<div className="location_tag">
<div>Location</div>
</div>
</div>
);
};
export default Location;
Идем в основной файл -
App.js подключаем
import Location from './Compomemts/Location';
и выводим этот компонент на страницу, сразу после последнего компонента.
В итоге у нас получится вот так:
Все файлы проекта на этом этапе смотрите в репо -
react-site-slider-abc
ci -m "Location section"
Подвал сайта - футер
На этом я остановлюсь коротко. У нас будет самый простой подвал, с самой простой разметкой. Пэтому мы создадим его в папке, которую создали еще в первой части, и в которой у нас все для хэдера-фуера.
Наша задача будет просто вывести разметку и задать ей некую задержку проявления - Fade.Ранее мы уже работали с этим эффектом и потому я останавливаться на этом подробно не буду.
src/Components/Header_Footer/Footer.js
import React from "react";
import Fade from "react-reveal/Fade";
const Footer = () => {
return (
<footer className="bck_red">
<Fade delay={500}>
<div className="font_righteous footer_logo_venue">
wmg react-meeting
</div>
<div className="footer_copyright">
The venue 2019. © All rights reserved.
<br />
Made by Kolesnikov Yaroslav
</div>
</Fade>
</footer>
);
};
export default Footer;
Добавляем стили:
resources/style.css
/* ====================>>> FOOTER <<<========================= */
footer {
padding:50px 0px;
text-align: center;
font-size: 60px;
color:#ffffff;
background: red;
}
footer .footer_copyright {
font-size: 18px;
}
Подключаем и выводим компонент на страницу - как обычно в файле
App.js
Все файлы проекта на этом этапе смотрите в репо -
react-site-slider-abc
ci -m "Footer section"