Создаем лендинг сайт с нуля: якорные ссылки меню #11
Сегодня настроим якорные ссылки для всех пунктов меню и кнопки «Перейти в каталог», это позволит использовать навигацию по нашему сайту, также проведем небольшой рефакторинг кода и вынесем некоторые части кода в отдельные компоненты для последующего удобства работы с ними.
Полезные ссылки:
- Шаблон лендинга, который мы будем делать, доступен в Figma по ссылке.
- Код данного урока доступен в репозитории GitHub по ссылке.
- Подписывайтесь на мой Дзен канал
Якорные ссылки
У нас в шаблоне есть ссылки в верхнем и нижнем меню, а также кнопка, ссылающаяся на секцию каталога.
Для начала нам необходимо проставить 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.
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 и заставим его работать на мобильных устройствах.
На сегодня всё!
В следующей статье мы сверстаем секцию Gallery.
Шаблон лендинга, который мы будем делать, доступен в Figma по ссылке.
Код данного урока доступен в репозитории GitHub по ссылке.
На этом всё, добавляйте сайт в избранное, чтобы не пропустить новых статей, а также подписывайтесь на мой Дзен-канал – dzen.ru/in9var