Сегодня настроим якорные ссылки для всех пунктов меню и кнопки «Перейти в каталог», это позволит использовать навигацию по нашему сайту, также проведем небольшой рефакторинг кода и вынесем некоторые части кода в отдельные компоненты для последующего удобства работы с ними.
Полезные ссылки:
Часть 1. Подготовка и настройка проекта
Часть 2. Настройка конфигурации и установка необходимых библиотек
Часть 3. Создание CSS-переменных и верстка блока Header
Часть 4. Верстка секции Hero, создание компонента Button
Часть 5. Верстка секции About
Часть 6. Верстка секции Gallery
Часть 7. Верстка секции WhyUs
Часть 8. Верстка секции Catalogue
Часть 9. Верстка секции Map
Часть 10. Верстка секции Footer
Часть 11. Создание якорных ссылок, рефакторинг
Часть 12. Создание мобильного меню
Часть 13. Анимация секций при скролле
Часть 14. Установка метаданных
Часть 15. Настройка Favicon.ico
Часть 16. Настройка счетчика Яндекс Метрики
Часть 17. Публикуем проект на хостинге
Якорные ссылки
У нас в шаблоне есть ссылки в верхнем и нижнем меню, а также кнопка, ссылающаяся на секцию каталога.
Для начала нам необходимо проставить id на те секции, на которые мы будем направлять ссылку, делается это очень просто, нам необходимо в перечисленных файлах указать уникальный идентификатор id.
Я не буду вставлять весь код каждого файла, просто перечислю их названия и отрывок кода.
page.jsx
... <main id='main'> ...
WhyUs.jsx
... <section id='about' className='flex w-full text-on-secondary bg-secondary'> ...
Catalogue.jsx
... <section id='products' className='w-full px-5 mx-auto max-w-screen-xl py-12 lg:py-32'> ...
Map.jsx
... <section id='contacts' className='flex w-full text-on-primary bg-primary'> ...
Теперь все ссылки вида «/#название_якоря» будут перемещать нас в необходимую секцию. Всё достаточно просто.
Компонент логотипа Logo.jsx
У нас на сайте есть повторяющийся элемент логотипа, чтобы не дублировать код и редактировать его из одного места, создадим в папке app/components/elements/ компонент Logo.jsx.
Содержимое файла Logo.jsx
import Link from 'next/link';
export default function Logo({ href }) {
return (
<Link href={href} className='font-black text-4xl'>
Логотип
</Link>
);
}
Теперь в Header.jsx и Footer.jsx мы можем импортировать наш новый компонент Logo.jsx и удалить часть старого кода.
... <Logo href={'/'} /> ...
Социальные иконки
Социальные иконки у нас также дублируются в Header.jsx и Footer.jsx. Создадим компонент Icon.jsx в папке app/components/elements/ и поместим в него следующий код:
import Link from 'next/link';
import { IoMdMail } from 'react-icons/io';
import { BiLogoTelegram } from 'react-icons/bi';
export default function Icon({ href, type }) {
return (
<Link href={href}>
<div className='flex bg-primary hover:brightness-110 rounded-md text-on-primary p-2 transition-all duration-200 ease-in-out'>
{type === 'email' && <IoMdMail className='flex bg-primary rounded-md text-on-primary' size={18} />}
{type === 'telegram' && <BiLogoTelegram className='flex bg-primary rounded-md text-on-primary' size={18} />}
</div>
</Link>
);
}
Данный компонент принимает в качестве параметров ссылку — href и тип — type, и на основании этого возвращает необходимую иконку с соответствующей ссылкой.
Теперь нам не надо редактировать в двух частях сайта код при изменении, например, адреса электронной почты.
Создадим компонент SocialIcons.jsx в папке app/components/blocks/.
Код данного компонента:
import Icon from '../elements/Icon';
export default function SocialIcons() {
return (
<div className='flex gap-6 items-start'>
<Icon href={'mailto:mail@email.ru'} type='email' />
<Icon href={'tg://resolve?domain=@someTgAccountName'} type='telegram' />
</div>
);
}
В этом компоненте мы размещаем иконки нужного типа в необходимом порядке.
Остается только обновить наши компоненты Header.jsx и Footer.jsx. Убираем из них старый кусок кода с иконками и вставляем наш компонент блока SocialIcons.jsx.
... <SocialIcons /> ...
Компонент ProductCard.jsx
Я решил вынести карточку товаров в отдельный компонент для удобства.
Создаем файл ProductCard.jsx в папке app/components/blocks/
код компонента ProductCard.jsx:
import ExportedImage from 'next-image-export-optimizer';
export default function ProductCard({ item }) {
return (
<div className='flex flex-col gap-5'>
<div className={`aspect-[4/3] overflow-hidden relative`}>
<ExportedImage
alt={'card image'}
src={item.src}
fill
loading='lazy'
placeholder='blur'
className={`object-cover`}
/>
</div>
<div className='flex flex-col gap-3'>
<h3 className='text-xl font-black'>{item.title}</h3>
<div className='flex justify-between'>
<div className='flex flex-col gap-3'>
<span className='font-black'>
<span className='font-light '>Площадь: </span>
{item.area} м²
</span>
<span className='font-black'>
<span className='font-light '>Этажи: </span>
{item.floors}
</span>
</div>
<div className='flex flex-col gap-3 items-end'>
<span className='font-black'>
<span className='font-light '>Спальни: </span>
{item.bedrooms}
</span>
<span className='font-light '> {item.material}</span>
</div>
</div>
<span className='text-xl font-black'>{`${item.price.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ' ')} ₽`}</span>
</div>
</div>
);
}
Теперь можем почистить компонент Catalogue.jsx.
код компонента Catalogue.jsx:
import { cardItems } from '@/app/cardItems';
import ProductCard from '../blocks/ProductCard';
export default function Catalogue() {
return (
<section id='products' className='w-full px-5 mx-auto max-w-screen-xl py-12 lg:py-32'>
<div className='grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 gap-14 lg:gap-10 w-full'>
{cardItems.map((item, index) => (
<ProductCard key={index} item={item} />
))}
</div>
</section>
);
}
После всех этих манипуляций код стал намного чище, и его гораздо удобнее рефакторить и поддерживать.
В следующей статье займемся BurgerMenu и заставим его работать на мобильных устройствах.
Код данного урока доступен в репозитории GitHub по ссылке.
Не забудь подписаться на канал, а также заходи на мой блог blog.in9var.ru, а также можешь посетить мой основной сайт — in9var.ru.