ساخت منوی همبرگری با قلاب های React — از صفر تا صد

۶۷۸ بازدید
آخرین به‌روزرسانی: ۱۹ شهریور ۱۴۰۲
زمان مطالعه: ۵ دقیقه
ساخت منوی همبرگری با قلاب های React — از صفر تا صد

اغلب افراد داشتن منوهای ساده را روی صفحه‌های وب ترجیح می‌دهند که موجب پرت شدن حواس مخاطب از محتوای اصلی صفحه نشود و در عین حال همواره در دسترس کاربران باشد. در این مقاله همراه با هم اقدام به ساخت منوی همبرگری با قلاب های React و کامپوننت‌های استایل‌دار می‌کنیم.

منوی همبرگری چیست؟

منوی همبرگری به منویی با آیکون سه خط افقی گفته می‌شود که شکل آن شبیه همبرگر است.

منوی همبرگری با قلاب های React

در این مقاله قصد داریم یک شکل ساده‌شده از منوی همبرگری که در تصویر فوق می‌بینید را بسازیم.

اجزای منوی همبرگری

ما کد منوی همبرگری خود را با استفاده از ری‌اکت نسخه 16.13، تایپ اسکریپت نسخه 3.8 و کامپوننت‌های استایل‌دار نسخه 5.1 نوشته‌ایم. البته شما می‌توانید بسته به ذائقه خود در این اجزای تشکیل‌دهنده منوی همبرگری تغییراتی ایجاد کنید.

کامپوننت‌های اولیه

معمولاً روش مناسب این است که ساخت کامپوننت‌های مورد نیاز خود را از کمترین حد ممکن آغاز کرده و در ادامه جزییاتی به آن اضافه کنیم. در این مسیر با موارد ضروری آشنا خواهید شد. اگر یک کاربر باتجربه هستید، می‌توانید مستقیماً به کد کامل که در انتهای مقاله ارائه شده است مراجعه کنید.

در کد ارائه شده زیر یک مبنای کمینه برای آغاز کار ارائه شده است. در ادامه ویرایش نسخه موبایل، گذارها و قلاب‌ها (رویدادهای کلیک) را اضافه می‌کنیم. کد خود را به دو بخش Menu و Hamburger تقسیم کرده‌ایم. به این ترتیب پس از افزودن بخش اولیه، منو به صورت زیر درمی‌آید:

منوی همبرگری با قلاب های React

منو

Menu آن ناحیه با پس‌زمینه قهوه‌ای است که شامل لینک‌های ناوبری است:

1import React, { useState } from "react";
2import styled from "styled-components";
3
4import { colors } from "../../global";
5
6import Hamburger from "../Hamburger/Hamburger";
7
8const StyledMenu = styled.nav<{ open: boolean }>`
9  top: 0;
10  left: 0;
11  height: 100vh;
12  width: 35vw;
13  position: fixed;
14  background-color: ${colors.lightbrown};
15  z-index: 1;
16  padding: 10rem 0;
17  flex-direction: column;
18  display: ${({ open }) => (open ? "flex" : "none")};
19`;
20const StyledLink = styled.a`
21  padding: 0 2rem;
22  font-size: 2rem;
23  color: ${colors.pearl};
24  text-decoration: none;
25  
26  :hover {
27    color: ${colors.yellowmellow};
28    cursor: pointer;
29  }
30`;
31
32const Menu = () => {
33  const [open, setOpen] = useState<boolean>(false);
34  const close = () => setOpen(false);
35  return (
36    <div>
37      <StyledMenu open={open}>
38        <StyledLink onClick={() => close()}>Link 1</StyledLink
39        <StyledLink onClick={() => close()}>Link 2</StyledLink
40        <StyledLink onClick={() => close()}>Link 3</StyledLink
41      </StyledMenu>
42      <Hamburger open={open} setOpen={setOpen} />
43     </div>
44   );
45};

Hamburger یک آیکون برای منوی نمادین است که به عنوان ابزاری برای پنهان و پیدا ساختن منو استفاده می‌شود:

1import React from "react";
2import styled from "styled-components";
3
4import { colors } from "../../global";
5
6const StyledHamburger = styled.button<{ open: boolean }>`
7  position: fixed;
8  left: 3vw;
9  top: 3vw;
10  width: 2rem;
11  height: 2rem;
12  padding: 0;
13  background: transparent;
14  
15  display: flex;
16  flex-direction: column;
17  justify-content: space-around;
18  border: none;
19  cursor: pointer;
20  outline: none;
21  z-index: 1;
22  div {
23    position: relative;
24    width: 2rem;
25    height: 0.25rem;
26    border-radius: 10px;
27    background-color: ${({ open }) =>
28      open ? colors.pearl : colors.lightbrown};
29  }
30`;
31
32type Props = {
33  open: boolean;
34  setOpen: (v: boolean) => void;
35};
36
37const Hamburger = (props: Props) => (
38  <StyledHamburger
39    open={props.open}
40    onClick={() => props.setOpen(!props.open)}
41  >
42    <div />
43    <div />
44    <div />
45  </StyledHamburger>
46);

افزودن برخی حرکت‌ها با استفاده از transition

اکنون منوی همبرگری اولیه خود را داریم. اگر فکر می‌کنید بیش از حد ساده است، در ادامه مقداری حرکت به آن اضافه می‌کنیم. ابتدا باید Menu و محتوای آن را با تغییرهای easing in و easing out انتقال دهیم.

برای این که بیشترین بهره را از Hamburger ببریم، می‌توانیم آن را در زمان بسته شدن منو، از یک شکل آیکون همبرگری به یک نشانه بسته شدن تبدیل کنیم. به این ترتیب دو آیکون در یک آیکون داریم. با این تغییرها، اینک منو باید به صورت زیر در آمده باشد:

منوی همبرگری با قلاب های React

1// Menu
2const StyledMenu = styled.nav<{ open: boolean }>`
3  //...
4  transition: transform 0.3s ease-in-out;
5  transform: ${({ open }) =>
6    (open ? "translateX(0)" :"translateX(-100%)")};
7`;
8
9// Hamburger
10const StyledHamburger = styled.button<{ open: boolean }>`
11  //...
12  left: ${({ open }) => (open ? "29vw" : "3vw")};
13  div {
14    //...
15    transition: all 0.3s linear;
16    transform-origin: 1px;
17  
18    :first-child {
19      transform: ${({ open }) =>
20        (open ? "rotate(45deg)" : "rotate(0)")};
21    }
22    :nth-child(2) {
23      opacity: ${({ open }) => (open ? "0" : "1")};
24      transform: ${({ open }) => 
25        (open ? "translateX(20px)":"translateX(0)")};
26    }
27    :nth-child(3) {
28      transform: ${({ open }) =>
29        (open ? "rotate(-45deg)" : "rotate(0)")};
30    }
31  }
32`;

روی منو با مقداری تأخیر فرایند ease in و ease out را اجرا می‌کنیم تا تحرک بیشتری ایجاد شود. در مورد بخش همبرگر بخش‌های اول و سوم را به میزان 25 درجه چرخش می‌دهیم تا یک شکل متقاطع ایجاد شود. Div دوم نیز پنهان می‌شود، زیرا برای ایجاد یک آیکون بستن تنها به دو بخش نیاز داریم. به این ترتیب موفق شدیم یک منوی همبرگری ایجاد کنیم.

تغییرات موبایل

به طور معمول بهتر است طراحی‌های خود را ساده حفظ کنیم تا تغییرهای زیادی برای موبایل نیاز نباشد، اما مهم است کاری کنیم که این منو روی صفحه‌های کوچک توجه زیادی را برنیانگیزد.

زمانی که به منوی خود روی صفحه‌های کوچک نگاه می‌کنیم، می‌بینیم که عملاً تمام صفحه را اشغال می‌کند. این وضعیت حس نمایش تبلیغات درون برنامه‌ای تمام صفحه را برای کاربر تداعی می‌کند که خوب نیست. ما در اپلیکیشن خود یک پس‌زمینه در عرض 600px ایجاد کرده‌ایم که Menu فوکوس تمام صفحه دریافت می‌کند. اکنون منوی ما روی صفحه‌های کوچک باید چیزی مانند تصویر زیر باشد:

منوی همبرگری با قلاب های React

1//Menu
2export const StyledMenu = styled.nav<{ open: boolean }>`
3  //...
4  @media (max-width: 600px) {
5    width: 100%;
6  }
7`;
8
9//Hamburger
10const StyledHamburger = styled.button<{ open: boolean }>`
11  //...
12  @media (max-width: 600px) {
13    left: ${({ open }) => (open ? "initial" : "3vw")};
14    right: ${({ open }) => (open ? "2vw" : "initial")};
15  }
16  //...
17`;

در مورد Menu صرفاً یک کوئری مدیا برای عرض منوی 100% به جای 30% عرض نما در مواردی که عرض صفحه 6000 پیکسل یا کمتر باشد ایجاد کرده‌ایم. در مورد بخش Hamburger باید آیکون صلیبی را در زمان باز شدن منو روی موبایل به طور کامل به سمت راست ببریم. وقتی که روی موبایل (حالت تمام صفحه‌) هستیم، باید به اندازه x مقدار از سمت راست فاصله بگیریم.

قلا‌ب‌ها

بخش Menu باید حالت خود را ردگیری کند و بداند که باید باز یا بسته بماند. این کار با استفاده از قلاب useState به همراه یک مقدار بولی open و تابع setOpen برای تغییر دادن حالت open به سادگی انجام می‌یابد. این چیزی است که قبلاً به Menu خود اضافه کرده‌ایم، چون بخشی ضروری برای کارکرد آن محسوب می‌شود.

1const [open, setOpen] = useState<boolean>(false);

در حال حاضر اگر کاربر خارج از منو کلیک کند، هیچ اتفاق خاصی نمی‌افتد. اما کاربر به طور معمول انتظار دارد که در این موقعیت منوی باز، بسته شود. برای این که بتوانیم تشخیص دهیم آیا کاربر درون یا بیرون منو کلیک کرده است، باید یک ارجاع گره به Menu اضافه کنیم. به این ترتیب می‌توانیم به این پاسخ که کاربر درون یا بیرون منو کلیک کرده است، پاسخ دهیم. همراه با این node می‌توانیم از یک قلاب سفارشی useOnClickOutside استفاده کنیم. نتیجه کار به صورت زیر است:

منوی همبرگری با قلاب های React

1import { useEffect, RefObject } from "react";
2
3const useOnClickOutside = (
4  ref: RefObject<HTMLDivElement>,
5  closeMenu: () => void
6) => {
7  useEffect(() => {
8    const listener = (event: MouseEvent) => {
9      if (ref.current && event.target &&
10        ref.current.contains(event.target as Node)
11      ) {
12        return;
13      }
14      closeMenu();
15    };
16    
17    document.addEventListener("mousedown", listener);
18    return () => {
19      document.removeEventListener("mousedown", listener);
20    };
21  }, [ref, closeMenu]);
22};
23const Menu = (props: Props) => {
24  const [open, setOpen] = useState<boolean>(false);
25  
26  const node = useRef<HTMLDivElement>(null);
27  useOnClickOutside(node, () => props.setOpen(false));
28  return (
29    <div ref={node}>
30      ....
31    </div>
32  );
33};

به این ترتیب به پایان این مقاله می‌رسیم. امیدواریم این مقاله را مفید یافته باشید. هر گونه دیدگاه یا پیشنهاد خود را در مورد این مقاله و پیاده‌سازی منوهای همبرگری با ما و دیگر خوانندگان مجله فرادرس در میان بگذارید.

اگر این مطلب برای شما مفید بوده است، آموزش‌های زیر نیز به شما پیشنهاد می‌شوند:

==

بر اساس رای ۲ نفر
آیا این مطلب برای شما مفید بود؟
اگر بازخوردی درباره این مطلب دارید یا پرسشی دارید که بدون پاسخ مانده است، آن را از طریق بخش نظرات مطرح کنید.
منابع:
javascript-in-plain-english
نظر شما چیست؟

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *