Найти в Дзене
in9var

Создаем крутой лендинг сайт с нуля: якорные ссылки меню #11

Сегодня настроим якорные ссылки для всех пунктов меню и кнопки «Перейти в каталог», это позволит использовать навигацию по нашему сайту, также проведем небольшой рефакторинг кода и вынесем некоторые части кода в отдельные компоненты для последующего удобства работы с ними. Полезные ссылки: Часть 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. Публикуем проект на хостинге У нас в шаблоне есть ссылки в верхнем
Оглавление

Сегодня настроим якорные ссылки для всех пунктов меню и кнопки «Перейти в каталог», это позволит использовать навигацию по нашему сайту, также проведем небольшой рефакторинг кода и вынесем некоторые части кода в отдельные компоненты для последующего удобства работы с ними.

Превью | Канал dzen.ru/in9var
Превью | Канал dzen.ru/in9var

Полезные ссылки:

Часть 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. Публикуем проект на хостинге

  • Демо–проект лендинга можно посмотреть по ссылке.
  • Шаблон лендинга, который мы будем делать, доступен в 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.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}&nbsp;м²
</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.