Hamburgare Meny med en Sida av Reagera Krokar och Utformade Komponenter

0
7

Vi vet alla vad en hamburgare meny är rätt? När mönstret började göra sin väg in web design, det blev både hånad och applåderade för sin minimalism som gör att huvudmenyerna för att sticka ut skärmen, särskilt på mobila där varje pixel av det utrymme som räknas.

CSS-Tricks är alla ungefär dubbelt kött.

Älskar dem eller hatar dem, hamburgare menyerna är här och sannolikt kommer att vara för en lång tid framöver. Problemet är hur man ska genomföra dem. Visst, de ser enkla och okomplicerade, men de kan vara vad som helst men. Till exempel bör de vara ihop med en etikett? Är de mer effektiva på vänster eller höger sida av skärmen? Hur kan vi ta itu med en stängning av dessa menyer, antingen genom att klicka eller trycka på? Bör ikonen vara en SVG, typsnitt, Unicode-tecken, eller ren CSS? Vad sägs om en meatless alternativ?

Jag ville bygga en av dem men misslyckades med att hitta en enkel lösning. De flesta lösningar bygger på bibliotek, som reactjs-popup eller reagera-burger-menyn. De är bra, men för mer komplexa lösningar. Vad sägs om den grundläggande användningen fallet med en tre-line meny som enkelt glider en panel ut från sidan av skärmen när man klickat på, sedan glider panelen igen när det klickade igen?

Jag bestämde mig för att bygga mig en egen enkel hamburgare med sidebar. Ingen pickles, lök och ketchup. Bara kött, bulle, och en sida med menyalternativ.

Är du redo att skapa det med mig?

Visa på CodePen Visa på GitHub

Det här är vad vi gör

Se Pennan
Burger meny med att Reagera krokar och stil-komponenter genom Maks Akymenko (@maximakymenko)
på CodePen.

Vi bygger använda Reagera för denna tutorial eftersom det verkar vara en bra användningsfall för det: vi får en återanvändbar komponent och en uppsättning av krokar vi kan förlänga för att hantera klicka på funktionalitet.

Snurra upp en ny Reagera-projekt

Låt oss snurra upp ett nytt projekt med skapa-reagera-app, ändra till den mapp och lägga till stil-komponenter till style UI:

npx skapa-reagera-app-dina-projekt-namn
cd-dina-projekt-namn
garn lägg till stil-komponenter

Lägg till grundläggande stilar

Öppna den nyskapade projekt i din favorit-editorn och börja lägga grundmodeller med stil-komponenter. I ditt src-katalog, skapa en fil som heter global.js. Det kommer att innehålla stilar för hela programmet. Du kan skriva din egen eller bara kopiera det jag slutade göra:

// global.js
import { createGlobalStyle } från ‘stil-komponenter”;

export const GlobalStyles = createGlobalStyle`
html, body {
margin: 0;
padding: 0;
}
*, *::efter att, *::innan {
box-sizing: border-box;
}
body {
align-objekt: center;
bakgrund: #0D0C1D;
färg: #EFFFFA;
display: flex;
font-family: -apple-system, BlinkMacSystemFont, “Segoe UI”, Roboto, Helvetica, Arial, sans-serif, “Apple Färg Emoji”, “Segoe UI Emoji”, “Segoe UI Symbol”;
höjd: 100vh;
motivera-innehåll: center;
sms: a-rendering: optimizeLegibility;
}
`

Detta är bara en del av den globala stilar, resten av den kan du hitta här.

Den CreateGlobalStyle funktionen används oftast för att skapa globala stilar som är exponerade för hela programmet. Vi kommer att importera det så att vi har tillgång till dessa stilar som vi går.

Nästa steg är att lägga till en tema-fil som innehåller alla våra variabler. Skapa ett theme.js fil i src-katalogen och lägg till följande:

// theme.js
export const tema = {
primaryDark: ‘#0D0C1D’,
primaryLight: ‘#EFFFFA’,
primaryHover: ‘#343078’,
mobil: ‘576px’,
}

Lägg till layout-menyn och hamburgare komponenter 🍔

Gå till din App.js fil. Vi kommer att torka ut allt ur det och skapa de viktigaste mall för vår app. Här är vad jag gjorde. Kan du verkligen skapa din egen.

// App.js
importera Reagerar från ‘reagerar’;
import { ThemeProvider } från ‘stil-komponenter”;
import { GlobalStyles } från”. /global’;
import { tema } från”. /temat”;

funktion App() {
avkastning (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hej. Detta är burger meny tutorial</h1>
<img src=”https://image.flaticon.com/icons/svg/2016/2016012.svg” alt=”burger ikonen” />
<small> – Ikonen som gjorts av Freepik från www.flaticon.com</small>
</div>
</>
</ThemeProvider>
);
}
export standard App;

Glöm inte att lägga till raden med små tag. Det är hur vi kredit flaticon.comhttp://flaticon.kom). författarna för den medföljande ikonen.

Här är vad vi har fått fram till denna punkt:

Låt mig förklara lite. Vi importerade ThemeProvider, som är en wrapper komponent som använder Sammanhang API bakom kulisserna för att göra vårt tema variabler som finns tillgängliga för att hela komponenten träd.

Vi har också importerat våra GlobalStyles och passerade dem som en del av vår app, vilket innebär att vår ansökan har nu tillgång till alla globala stilar. Som du kan se, vår GlobalStyles komponent är inne ThemeProvider vilket innebär att vi kan redan göra några mindre ändringar i det.

Gå till global.js och ändra bakgrunden och färg egenskaper för att använda vår definierade variabler. Detta hjälper oss att genomföra ett tema snarare än att använda fasta värden som är svåra att ändra.

// global.js
bakgrund: ${({ tema }) => tema.primaryDark};
färg: ${({ tema }) => tema.primaryLight};

Vi destructure vårt tema från props. Så, istället för att skriva rekvisita.tema varje gång, vi använder oss av ett gäng konsoler istället. Jag ska upprepa mig: det tema som är tillgängliga beror på att vi har insvept vår globala stilar med ThemeProvider.

Skapa Burger Meny och komponenter

Skapa ett komponenter mapp i src-katalogen och lägg till två mappar i det: Meny och Hamburgare, plus en index.js fil.

index.js kommer att användas för ett syfte: att möjliggöra för oss att importera komponenter från en fil, vilket är mycket praktiskt, särskilt när du har en hel del av dem.

Nu ska vi skapa vår komponenter. Varje mapp innehåller tre filer.

Vad är upp med alla filer? Du kommer att se fördelarna med en skalbar struktur snart nog. Det fungerade bra för mig i ett par projekt, men här är bra råd för hur du kan skapa skalbar struktur.

Gå till Burger mapp och skapa Burger.js för vår layout. Lägg sedan till Burger.styled.js som kommer att innehålla stilar, och index.js. som kommer att exportera filen.

// index.js
export { default } från”. /Burger’;

Känn dig fri att forma burgare växla på ett sätt som du vill, eller bara klistra in dessa stilar:

// Burger.styled.js
importera stil från ‘stil-komponenter”;

export const StyledBurger = inredda.knapp”
position: absolute;
topp: 5 procent.
vänster: 2rem;
display: flex;
flex-riktning: kolumnen.
motivera-innehåll: space-runt;
bredd: 2rem;
höjd: 2rem;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;

&:focus {
utkast: none;
}

div {
bredd: 2rem;
höjd: 0.25 rem;
bakgrund: ${({ tema }) => tema.primaryLight};
border-radius: 10px;
övergång: alla 0.3 s linjär;
position: relative;
förvandla-ursprung: 1px;
}
`;

Transform-ursprung fastigheten kommer att behövas senare för att animera menyn det växlar mellan öppna och slutna stater.

Efter att ha lagt stilar, gå till Burger.js och lägg till den layout:

// Burger.js
importera Reagerar från ‘reagerar’;
import { StyledBurger } från”. /Burger.stil’;

const Burger = () => {
avkastning (
<StyledBurger>
<p />
<p />
<p />
</StyledBurger>
)
}

export standard Burger;

Efter att titta på den vänstra övre hörnet. Ser du på det?

Dags att göra samma sak med Menyn mappen:

/ Av/ meny -> index.js
export { default } från”. /Meny’;

// Menu.styled.js
importera stil från ‘stil-komponenter”;

export const StyledMenu = inredda.nav”
display: flex;
flex-riktning: kolumnen.
motivera-innehåll: center;
bakgrund: ${({ tema }) => tema.primaryLight};
höjd: 100vh;
text-align: left;
stoppning: 2rem;
position: absolute;
top: 0;
left: 0;
övergången till: omvandla 0.3 s ease-in-out;

@media (max-width: ${({ tema }) => tema.mobil}) {
width: 100%;
}

en {
font-size: 2rem;
text-transform: uppercase;
stoppning: 2rem 0;
font-weight: bold;
letter-spacing: 0.5 rem;
färg: ${({ tema }) => tema.primaryDark};
text-decoration: none;
övergång: färg 0.3 s linjär;

@media (max-width: ${({ tema }) => tema.mobil}) {
font-size: 1.5 rem;
text-align: center;
}

&:hover {
färg: ${({ tema }) => tema.primaryHover};
}
}
`;

Nästa, låt oss lägga till layout för de menyalternativ som visas när du klickar på våra burgare:

// Menu.js
importera Reagerar från ‘reagerar’;
import { StyledMenu } från”. /Menyn.stil’;

const Meny = () => {
avkastning (
<StyledMenu>
<a href=”/”>
<span roll=”img” aria-label=”om oss”>&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Om oss
</a>
<a href=”/”>
<span roll=”img” aria-label=”pris”>&#x1f4b8;</span>
Prissättning
</a>
<a href=”/”>
<span roll=”img” aria-label=”kontakt”>&#x1f4e9;</span>
Kontakta
</a>
</StyledMenu>
)
}
export-standard på Menyn;

Vi har fått fin emojis här, och det är bäst att göra dem tillgängliga genom att linda var och en i en spann och lägga till ett par egenskaper: roll=”img” och aria-label=”etikett”. Du kan läsa mer om det här.

Dags att importera vår nya komponenter i vår App.js fil:

// App.js
importera Reagerar från ‘reagerar’;
import { ThemeProvider } från ‘stil-komponenter”;
import { GlobalStyles } från”. /global’;
import { tema } från”. /temat”;
import { Burger, Meny } från”. /komponenter”;

// …

Låt oss se vad vi har:

Ta en titt på denna fina navigation bar! Men vi har fått en fråga här: är det öppnade, och vi vill att det initialt att vara stängt. Vi behöver bara lägga till en rad till Menu.styled.js fixa det:

// Menu.styled.js
förändra: ‘translateX(-100%)’;

Vi är på god väg att kalla detta för burger kokta! Men först…

Lägga öppna och stänga funktionalitet

Vi vill öppna sidofältet när du klickar på hamburger ikonen, så låt oss få till det. Öppna App.js och lägga till några tillstånd till det. Vi kommer att använda useState krok för det.

// App.js
importera Reagera, { useState } från ‘reagerar’;

När du har importerat, låt oss använda den inuti Appen komponent.

// App.js
const [öppna, setOpen] = useState(false);

Vi sätter den initiala tillstånd till false, eftersom vår meny ska vara dolda när ansökan görs.

Vi behöver både våra växla och sidomenyn för att veta om staten, så pass det ner som en stötta för att varje komponent. Nu är din App.js bör se ut ungefär så här:

// App.js
importera Reagera, { useState } från ‘reagerar’;
import { ThemeProvider } från ‘stil-komponenter”;
import { GlobalStyles } från”. /global’;
import { tema } från”. /temat”;
import { Burger, Meny } från”. /komponenter”;

funktion App() {
const [öppna, setOpen] = useState(false);
avkastning (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hej. Detta är burger meny tutorial</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animerad burger” />
</div>
<div>
<Burger öppna={öppen} setOpen={setOpen} />
<Meny öppna={öppen} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
export standard App;

Märker att vi är inslagning våra komponenter i en div. Detta kommer att vara till hjälp när vi senare lägga till funktioner som stänger menyn när du klickar var som helst på skärmen.

Hantera rekvisita i komponenterna

Våra Burgare och en Meny som vet om staten, så allt vi behöver göra är att hantera det inne och lägg stilar i enlighet med detta. Gå till Burger.js och hantera den rekvisita som har gått ner:

// Burger.js
importera Reagerar från ‘reagerar’;
import { bool, func } från “prop-typer’;
import { StyledBurger } från”. /Burger.stil’;
const Burger = ({ öppen, setOpen }) => {
avkastning (
<StyledBurger öppna={öppen} onClick={() => setOpen(!öppna)}>
<p />
<p />
<p />
</StyledBurger>
)
}
Burger.propTypes = {
öppet: bool.isRequired,
setOpen: func.isRequired,
};
export standard Burger;

Vi destructure den öppna och setOpen rekvisita och skicka dem till vår StyledBurger för att lägga till stilar för varje prop, respektive. Vi kan också lägga till onClick-hanterare för att ringa till vår setOpen funktion och växla mellan öppna prop. I slutet av filen, lägger vi typ kolla, som anses vara en av bästa praxis för att anpassa argument med förväntade data.

Du kan kontrollera om det fungerar eller inte genom att gå till din reagera-dev-tools. Gå till fliken Komponenter i din Chrome DevTools och klicka på Burger fliken.

När du nu klickar på din Burgare komponent, (inte blanda upp det med tab), bör du se till att ditt öppna kryssrutan är att ändra sitt tillstånd.

Gå till Menu.js och gör nästan samma sak, även om, här passerar vi endast öppet prop:

// Menu.js
importera Reagerar från ‘reagerar’;
import { bool } från “prop-typer’;
import { StyledMenu } från”. /Menyn.stil’;
const Meny = ({ öppen }) => {
avkastning (
<StyledMenu öppna={öppen}>
<a href=”/”>
<span roll=”img” aria-label=”om oss”>&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Om oss
</a>
<a href=”/”>
<span roll=”img” aria-label=”pris”>&#x1f4b8;</span>
Prissättning
</a>
<a href=”/”>
<span roll=”img” aria-label=”kontakt”>&#x1f4e9;</span>
Kontakta
</a>
</StyledMenu>
)
}
Menyn.propTypes = {
öppet: bool.isRequired,
}
export-standard på Menyn;

Nästa steg är att passera öppna prop ner till vår stylad komponent så att vi kunde gäller övergången. Öppna Menu.styled.js och lägg till följande till vår omvandla fastigheten:

förändra: ${({ öppen }) => open ? ‘translateX(0)’ : ‘translateX(-100%)’};

Detta är för att kontrollera om våra stylad komponent öppna prop är sann, och om så är fallet, lägger translateX(0) för att flytta våra navigering tillbaka på skärmen. Redan nu kan du testa det lokalt!

Vänta, vänta, vänta!

Märkte du något fel när du checkar ut saker och ting? Våra Hamburgare har samma färg som bakgrundsfärgen på vår Meny, som gör att de smälter samman. Låt oss ändra på det och också att animera ikonen för lite för att göra det mer intressant. Vi har öppet prop gått till det, så vi kan använda det för att tillämpa ändringarna.

Öppna Burger.styled.js och skriv följande:

// Burger.styled.js
importera stil från ‘stil-komponenter”;
export const StyledBurger = inredda.knapp”
position: absolute;
topp: 5 procent.
vänster: 2rem;
display: flex;
flex-riktning: kolumnen.
motivera-innehåll: space-runt;
bredd: 2rem;
höjd: 2rem;
background: transparent;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;

&:focus {
utkast: none;
}

div {
bredd: 2rem;
höjd: 0.25 rem;
bakgrund: ${({ tema, öppen }) => open ? temat.primaryDark : tema.primaryLight};
border-radius: 10px;
övergång: alla 0.3 s linjär;
position: relative;
förvandla-ursprung: 1px;

:first-child {
förändra: ${({ öppen }) => open ? ‘rotate(45deg)’ : ‘rotate(0)’};
}

:nth-child(2) {
opacitet: ${({ öppen }) => open ? ‘0’ : ‘1’};
förändra: ${({ öppen }) => open ? ‘translateX(20px)’ : ‘translateX(0)’};
}

:nth-child(3) {
förändra: ${({ öppen }) => open ? ‘rotate(-45deg)’ : ‘rotate(0)’};
}
}
`;

Detta är en stor bit av CSS, men det gör animation magiska hända. Vi kolla om den öppna prop är sant och ändra format i enlighet med detta. Vi roterar, översätta, sedan dölja menu-ikonen linjer medan du byter färg. Vacker, är det inte?

Okej, gott folk! Nu, bör du vet hur man skapar en enkel hamburgare ikonen och meny, som innehåller lyhördhet och smidig animation. Grattis!

Men det är en sista sak vi borde konto för…

Stäng menyn genom att klicka utanför den

Denna del känns som en liten bonus, men det är en stor UX vinna eftersom det tillåter användaren att stänga menyn genom att klicka någon annanstans på sidan. Detta hjälper användaren att undvika att behöva re-lokalisera-menyn och klicka exakt på det.

Vi kommer att lägga mer Reagera krokar att använda för att göra detta hända! Skapa en fil i src-katalog, som kallas hooks.js och öppna den. För detta, vi ska vända sig till useEffect krok, som infördes Reagera 18.

// hooks.js
import { useEffect } från ‘reagerar’;

Innan vi skriva kod, låt oss tänka på logiken bakom denna krok. När vi klickar någonstans på sidan, vi måste kolla om den klickade del är vår aktuella elementet (i vårt fall, som är den Meny komponent) eller om de klickat element innehåller den aktuella elementet (till exempel, våra div som sveper vår meny och hamburger-ikonen). Om så, vi behöver inte göra något, annars kan vi kalla en function, som vi ska nämna föraren.

Vi kommer att använda ref för att kontrollera klickat element, och vi kommer att göra så varje gång någon klickar på sidan.

// hooks.js
import { useEffect } från ‘reagerar’;

export const useOnClickOutside = (ref, handler) => {
useEffect(() => {
const lyssnaren = evenemanget => {
if (!ref.nuvarande || ref.aktuella.innehåller(händelse.målet)) {
återvändande.
}
handler(event);
};
dokumentet.addEventListener(‘mousedown’, lyssnare);
return () => {
dokumentet.removeEventListener(‘mousedown’, lyssnare);
};
},
[ref, handler],
);
};

Glöm inte att återvända funktionen från useEffect. Det är så kallade “clean up” och i grund och botten, det står för att ta bort en händelselyssnare när komponenten avmonterar. Det är utbyte av componentWillUnmount livscykel.

Låt oss nu koppla upp kroken

Vi har fått vår krok redo, så det är dags att lägga till den i appen. Gå till App.js filen finns och importera två krokar: det nybildade useOnClickOutside och även useRef. Vi kommer senare att få en referens till elementet.

// App.js
importera Reagera, { useState, useRef } från ‘reagerar’;
import { useOnClickOutside } från”. /krokar’;

För att få tillgång till dessa i det aktuella elementet (det element vi behöver för att få tillgång till DOM nod. Det är där vi använder useRef, även namn node perfekt speglar punkt för denna variabel.

Från det, vi passerar den nod som första argument. Vi kommer att passera den funktion som stänger vår meny som andra argument.

// App.js
const node = useRef();
useOnClickOutside(nod, () => setOpen(falskt));

Slutligen, vi måste gå vår ref till DOM-element. I vårt fall kommer det att vara div, som håller Hamburgare och Menyn komponenter:

// App.js
<div ref={node}>
<Burger öppna={öppen} setOpen={setOpen} />
<Meny öppna={öppen} setOpen={setOpen} />
</div>

Din App.js bör se ut ungefär så här:

// App.js
importera Reagera, { useState, useRef } från ‘reagerar’;
import { ThemeProvider } från ‘stil-komponenter”;
import { useOnClickOutside } från”. /krokar’;
import { GlobalStyles } från”. /global’;
import { tema } från”. /temat”;
import { Burger, Meny } från”. /komponenter”;
funktion App() {
const [öppna, setOpen] = useState(false);
const node = useRef();
useOnClickOutside(nod, () => setOpen(falskt));
avkastning (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hej. Detta är burger meny tutorial</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animerad burger” />
</div>
<div ref={node}>
<Burger öppna={öppen} setOpen={setOpen} />
<Meny öppna={öppen} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
export standard App;

Kolla in det här! Det fungerar som förväntat, och det är fullt funktionell och lyhörd.

Grattis, alla! Du gjorde ett bra jobb! Glad kodning!

Visa på GitHub