Hamburger-Meny med en Side av Reagere Kroker og Stil Komponenter

0
7

Vi vet alle hva en hamburger meny er, ikke sant? Når mønsteret begynte å gjøre sin vei inn web design, det var både lo og ros for sin minimalisme som gjør viktigste menyene for å bli stukket av skjermen, spesielt på mobile der hver piksel på plass teller.

CSS-Triks er alt om dobbel kjøtt.

Elsker dem eller hater dem, hamburger menyer er her og sannsynligvis vil være i noen tid fremover. Problemet er hvordan man skal implementere dem. Jada, de ser enkel og grei, men de kan være noe men. For eksempel, bør de settes sammen med en etikett? Er de mer effektive på venstre eller høyre side av skjermen? Hvordan kan vi takle lukke disse menyene, enten ved klikk eller trykk? Bør ikonet være en SVG -, skrift -, Unicode-tegn, eller pure CSS? Hva om en meatless alternativet?

Jeg ønsket å bygge en av dem, men klarte ikke å finne en enkel løsning. De fleste løsningene er basert på bibliotekene, som reactjs-popup eller reagere-burger-meny. De er flotte, men for mer komplekse løsninger. Hva om kjernen bruke tilfelle av en tre-linje-menyen, som bare glir en panelet ut fra siden av skjermen når den klikkes, så glir panelet tilbake i når den klikkes igjen?

Jeg bestemte meg å bygge min egen, enkel hamburger med sidefelt. Ingen pickles, løk eller ketchup. Bare kjøtt, bun, og en side av menyen.

Er du klar til å lage det med meg?

Se på CodePen Se på GitHub

Her er hva vi gjør

Se Penn
Burger meny Reagere med kroker og stylet-komponenter ved Maks Akymenko (@maximakymenko)
på CodePen.

Bygger vi bruke Reagere for denne opplæringen fordi det virker som et godt eksempel på bruk for det: vi får en gjenbrukbar komponent og et sett med kroker kan vi utvide til å håndtere klikk funksjonalitet.

Spinn opp en ny Reagere prosjektet

La oss starte opp et nytt prosjekt med å lage reagere-app, kan du endre til mappen katalog og legge til stil-komponenter til å style UI:

npx lage reagere-appen din-prosjekt-navn
cd-din-prosjekt-navn
garn legge til stil-komponenter

Legg til grunnleggende stiler

Åpne den nyopprettede prosjektet i din favoritt-kode editor, og du kan begynne å legge til grunnleggende stiler ved hjelp av stylet-komponenter. I src-katalogen, kan du opprette en fil som heter global.js. Det vil inneholde stiler for hele programmet. Du kan skrive inn din egen eller bare kopiere det jeg endte opp med å gjøre:

// global.js
import { createGlobalStyle } fra ‘stylet-komponenter’;

eksport const GlobalStyles = createGlobalStyle`
html, body {
margin: 0;
padding: 0;
}
*, *::etter, *::før {
safe-dimensjonering: border-box;
}
body {
juster-elementer: center;
bakgrunn: #0D0C1D;
color: #EFFFFA;
skjerm: flex;
font-family: -apple-systemet, BlinkMacSystemFont, “Segoe UI”, Roboto, Helvetica, Arial, sans-serif “Apple-Farge Emoji-tegn”, “Segoe UI Emoji-tegn”, “Segoe UI Symbol”;
høyde: 100vh;
rettferdiggjøre-innhold: center;
tekst-gjengivelse: optimizeLegibility;
}
`

Dette er bare en del av global stiler, resten av det du kan finne her.

Den CreateGlobalStyle funksjonen er generelt brukt for å skape global stiler som er eksponert for hele programmet. Vi vil importere det slik at vi har tilgang til disse stiler mens vi går.

Neste trinn er å legge til et tema-fil som inneholder alle våre variabler. Opprette en theme.js fil i src-katalogen, og legg til følgende:

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

Legg til layout, meny og hamburger komponenter 🍔

Gå til App.js fil. Vi kommer til å tørke alt ut av det og lage den viktigste mal for vår app. Her er hva jeg gjorde. Du kan sikkert lage din egen.

// App.js
import Reagere fra “reagerer’;
import { ThemeProvider } fra ‘stylet-komponenter’;
import { GlobalStyles } fra ‘./global’;
import { tema } fra ‘./tema’;

funksjonen App() {
retur (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hei. Dette er burger meny opplæringen</h1>
<img src=”https://image.flaticon.com/icons/svg/2016/2016012.svg” alt=”burger-ikonet” />
<small>Ikonet laget av Freepik fra www.flaticon.com</small>
</div>
</>
</ThemeProvider>
);
}
eksport-standard-App;

Ikke glem å legge til linjen med små tag. Det er hvordan vi kreditt flaticon.comhttp://flaticon.com) forfattere for gitt-ikonet.

Her er hva vi har fått opp til dette punktet:

La meg forklare litt. Vi har importert ThemeProvider, som er en wrapper komponent som bruker Sammenheng API bak kulissene for å gjøre vårt tema variabler tilgjengelig for hele komponenten treet.

Vi har også importert våre GlobalStyles og passert dem som en komponent i vår app, noe som betyr at vår søknad har nå tilgang til alle globale stiler. Som du kan se, våre GlobalStyles komponent er inne ThemeProvider noe som betyr at vi kan allerede gjøre noen mindre endringer i det.

Gå til global.js og endre bakgrunnen og farge egenskaper for å bruke vår definerte variabler. Dette hjelper oss med å gjennomføre et tema heller enn å bruke faste verdier som er vanskelig å endre.

// global.js
bakgrunn: ${({ tema }) => tema.primaryDark};
farge: ${({ tema }) => tema.primaryLight};

Vi destructure vårt tema fra rekvisitter. Så, i stedet for å skrive rekvisitter.tema hver gang vi bruker en haug av braketter i stedet. Jeg vil gjenta meg selv: det tema er tilgjengelig fordi vi har pakket vår globale stiler med ThemeProvider.

Lage Burger Meny og komponenter

Opprette en komponenter mappe i src-katalogen, og legg til to mapper i det: Meny og Burger, pluss en index.js fil.

index.js vil bli brukt for ett formål: å tillate oss å importere komponenter fra en fil, som er svært nyttig, spesielt når du har masse av dem.

La oss nå lage våre komponenter. Hver mappe inneholder tre filer.

Hva er opp med alle filene? Du vil se fordelen av en skalerbar struktur snart nok. Det fungerte bra for meg i et par prosjekter, men her er gode råd til hvordan å lage skalerbare struktur.

Gå til Burger-mappen og skape Burger.js for vår layout. Deretter legg til Burger.styled.js som vil inneholde stiler, og index.js. som vil eksportere filen.

// index.js
eksport { standard,} fra ‘./Burger’;

Føl deg fri til å stil burger veksle på en måte du vil, eller bare lim inn disse stiler:

// Burger.styled.js
import stylet fra ‘stylet-komponenter’;

eksport const StyledBurger = stylet.knappen`
position: absolute;
øverst: 5%;
venstre: 2rem;
skjerm: flex;
flex-retning: kolonne;
rettferdiggjøre-innhold: plass-rundt;
bredde: 2rem;
høyde: 2rem;
bakgrunn: transparent;
ramme: ingen;
cursor: pointer;
padding: 0;
z-index: 10;

&:fokus {
disposisjon: ingen;
}

div {
bredde: 2rem;
høyde: 0.25 rem;
bakgrunn: ${({ tema }) => tema.primaryLight};
border-radius: 10px;
overgang: alle 0.3 s lineær;
position: relative;
transform-opprinnelse: 1px;
}
`;

Transform-opprinnelse eiendom vil være behov for senere å animere menyen den veksler mellom åpne og lukkede stater.

Etter å legge til stiler, kan du gå til Burger.js og legge til oppsettet:

// Burger.js
import Reagere fra “reagerer’;
import { StyledBurger } fra ‘./Burger.stylet’;

const Burger = () => {
retur (
<StyledBurger>
<div />
<div />
<div />
</StyledBurger>
)
}

eksport standard Burger;

Etter at se på den øverste venstre hjørne. Ser du det?

Tid til å gjøre det samme med Meny-mappen:

// Meny -> index.js
eksport { standard,} fra ‘./Meny’;

// Menu.styled.js
import stylet fra ‘stylet-komponenter’;

eksport const StyledMenu = stylet.nav`
skjerm: flex;
flex-retning: kolonne;
rettferdiggjøre-innhold: center;
bakgrunn: ${({ tema }) => tema.primaryLight};
høyde: 100vh;
text-align: left;
polstring: 2rem;
position: absolute;
øverst: 0;
venstre: 0;
overgang: forvandle 0.3 s letthet-i-ut;

@media (maks bredde: ${({ tema }) => tema.mobile}) {
bredde: 100%;
}

en {
font-size: 2rem;
text-transform: uppercase;
polstring: 2rem 0;
font-weight: bold;
brev-avstand: 0.5 rem;
farge: ${({ tema }) => tema.primaryDark};
text-decoration: none;
overgang: farge 0.3 s lineær;

@media (maks bredde: ${({ tema }) => tema.mobile}) {
font-størrelse: 1,5 rem;
text-align: center;
}

&:hover {
farge: ${({ tema }) => tema.primaryHover};
}
}
`;

Neste, la oss legge til oppsettet for menyelementene som er avslørt ved å klikke på vår burger:

// Menu.js
import Reagere fra “reagerer’;
import { StyledMenu } fra ‘./Meny.stylet’;

const Meny = () => {
retur (
<StyledMenu>
<a href=”/”>
<span rolle=”img” aria-label=”om oss” – >&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Om oss
</a>
<a href=”/”>
<span rolle=”img” aria-label=”price”>&#x1f4b8;</span>
Priser
</a>
<a href=”/”>
<span rolle=”img” aria-label=”kontakt”>&#x1f4e9;</span>
Kontakt
</a>
</StyledMenu>
)
}
eksport-standard Meny;

Vi har fått hyggelig emojis her, og beste praksis er å gjøre dem tilgjengelige ved å pakke hver og en i en periode og legger til et par egenskaper: role=”img” og aria-label=”ditt navn”. Du kan lese mer om det her.

Tid til å importere våre nye komponenter i vår App.js fil:

// App.js
import Reagere fra “reagerer’;
import { ThemeProvider } fra ‘stylet-komponenter’;
import { GlobalStyles } fra ‘./global’;
import { tema } fra ‘./tema’;
import { Burger, Meny } fra ‘./komponenter’;

// …

La oss se, hva vi har fått:

Ta en titt på denne fine navigasjon bar! Men vi har et problem her: det er åpnet, og vi ønsker i utgangspunktet å være lukket. Vi trenger bare å legge til en linje til Menu.styled.js fikser du det:

// Menu.styled.js
forvandle: ‘translateX(-100%)’;

Vi er godt på vei til å kalle dette burger kokt! Men først…

Legge til åpne og lukke funksjonalitet

Vi ønsker å åpne sidepanel ved å klikke på hamburger-ikonet, så la oss få til det. Åpen App.js og legg til noen tilstand til det. Vi vil bruke useState krok for det.

// App.js
import Reagere, { useState } fra “reagerer’;

Når du importerer det, la oss bruke den i App ‘ en komponent.

// App.js
const [åpne, setOpen] = useState(false);

Vi satte den første staten til å falsk, fordi vår meny bør være skjult når programmet er gjengitt.

Vi trenger både veksle og sidemeny å vite om staten, så gi det ned som en rekvisitt til hver komponent. Nå dine App.js skal se noe som dette:

// App.js
import Reagere, { useState } fra “reagerer’;
import { ThemeProvider } fra ‘stylet-komponenter’;
import { GlobalStyles } fra ‘./global’;
import { tema } fra ‘./tema’;
import { Burger, Meny } fra ‘./komponenter’;

funksjonen App() {
const [åpne, setOpen] = useState(false);
retur (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hei. Dette er burger meny opplæringen</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animerte burger” />
</div>
<div>
<Burger open={åpne} setOpen={setOpen} />
<Meny for å åpne={åpne} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
eksport-standard-App;

Legg merke til at vi innpakning våre komponenter i en div. Dette vil være nyttig når du senere vi legge til funksjonalitet som lukker menyen ved å klikke hvor som helst på skjermen.

Håndtere rekvisitter i komponenter

Vår Burger og Meny vet om tilstanden, så alt vi trenger å gjøre er å håndtere det på innsiden og legge til stiler i henhold til dette. Gå til Burger.js og håndtere rekvisitter som var gått ned:

// Burger.js
import Reagere fra “reagerer’;
import { bool, func } fra ‘prop-typer’;
import { StyledBurger } fra ‘./Burger.stylet’;
const Burger = ({ åpne, setOpen }) => {
retur (
<StyledBurger open={åpne} onClick={() => setOpen(!åpne)}>
<div />
<div />
<div />
</StyledBurger>
)
}
Burger.propTypes = {
åpne: bool.isRequired,
setOpen: func.isRequired,
};
eksport standard Burger;

Vi destructure åpne og setOpen rekvisitter og sende dem til våre StyledBurger å legge til stiler for hver prop, henholdsvis. Også, vi legge til onClick å ringe vår setOpen funksjon og veksle mellom åpne prop. På slutten av filen, vil vi legge til type kontroll, som regnes som en beste praksis for å justere argumenter med forventede data.

Du kan sjekke om det virker eller ikke, ved å gå til din reagerer-dev-verktøy. Gå til Komponenter fane i Chrome-DevTools og klikk på Burger kategorien.

Nå, når du klikker på Burger komponent, (ikke bland det opp med den kategorien), skal du se, at de åpne avkrysningsboksen er å endre sin tilstand.

Gå til Menu.js og gjør nesten det samme, selv om, her passerer vi bare åpne prop:

// Menu.js
import Reagere fra “reagerer’;
import { bool } fra ‘prop-typer’;
import { StyledMenu } fra ‘./Meny.stylet’;
const Meny = ({ åpne }) => {
retur (
<StyledMenu open={åpne}>
<a href=”/”>
<span rolle=”img” aria-label=”om oss” – >&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Om oss
</a>
<a href=”/”>
<span rolle=”img” aria-label=”price”>&#x1f4b8;</span>
Priser
</a>
<a href=”/”>
<span rolle=”img” aria-label=”kontakt”>&#x1f4e9;</span>
Kontakt
</a>
</StyledMenu>
)
}
Meny.propTypes = {
åpne: bool.isRequired,
}
eksport-standard Meny;

Neste trinn er å passere åpne prop ned til vår stylet komponent slik at vi kunne søke overgang. Åpen Menu.styled.js og legge følgende til vår forvandle eiendommen:

forvandle: ${({ åpne }) => åpne ? ‘translateX(0)’ : ‘translateX(-100%)’};

Dette er for å sjekke om vår stil komponent åpne prop er sant, og hvis så, det legger translateX(0) til å flytte vår navigering tilbake på skjermen. Du kan allerede teste det ut lokalt!

Vent, vent, vent!

Gjorde du oppdager noe galt når du sjekker ut ting? Vår Burger har samme farge som bakgrunnsfargen på vår Meny, noe som gjør dem blandes sammen. La oss endre dette og også animere ikonet litt for å gjøre det mer interessant. Vi har åpent prop gått til det, slik at vi kan bruke det til å ta i bruk endringene.

Åpen Burger.styled.js og skriv følgende:

// Burger.styled.js
import stylet fra ‘stylet-komponenter’;
eksport const StyledBurger = stylet.knappen`
position: absolute;
øverst: 5%;
venstre: 2rem;
skjerm: flex;
flex-retning: kolonne;
rettferdiggjøre-innhold: plass-rundt;
bredde: 2rem;
høyde: 2rem;
bakgrunn: transparent;
ramme: ingen;
cursor: pointer;
padding: 0;
z-index: 10;

&:fokus {
disposisjon: ingen;
}

div {
bredde: 2rem;
høyde: 0.25 rem;
bakgrunn: ${({ tema, åpne }) => åpne ? tema.primaryDark : tema.primaryLight};
border-radius: 10px;
overgang: alle 0.3 s lineær;
position: relative;
transform-opprinnelse: 1px;

:first-child {
forvandle: ${({ åpne }) => åpne ? ” roter(45deg)’ : ‘roter(0)’};
}

:nth-child(2) {
dekkevne: ${({ åpne }) => åpen ? ‘0’ : ‘1’};
forvandle: ${({ åpne }) => åpne ? ‘translateX(20 piksler)’ : ‘translateX(0)’};
}

:nth-child(3) {
forvandle: ${({ åpne }) => åpne ? ” roter(-45deg)’ : ‘roter(0)’};
}
}
`;

Dette er en stor del av CSS, men det gjør animasjon magiske skje. Vi sjekker om den åpne prop som er sant og endre stiler i henhold til dette. Vi rotere, oversette, så skjul på meny-ikonet linjer mens du skifter farge. Vakker, ikke sant?

Ok, folkens! Nå, bør du vite hvordan du oppretter en enkel hamburger-ikonet og meny, som inkorporerer respons og smidig animasjon. Gratulerer!

Men det er en siste ting vi burde konto for…

Lukke menyen ved å klikke på utsiden av det

Denne delen virker som en liten bonus, men det er en stor UX vinne fordi det tillater brukeren å lukke menyen ved å klikke hvor som helst annet sted på siden. Dette hjelper brukeren til å unngå å måtte finne på meny-ikonet og klikke nøyaktig på det.

Vi kommer til å sette mer Reagere kroker å bruke for å få dette til å skje! Opprett en fil i src-katalogen, kalt hooks.js og åpne det. For dette, vi kommer til å slå til useEffect kroken, som ble innført i Reagerer 18.

// hooks.js
import { useEffect } fra “reagerer’;

Før vi skriver koden, la oss tenke på logikken bak denne kroken. Når vi klikker på et sted på siden, vi må sjekke om klikket element er vår nåværende element (i vårt tilfelle, er at Menyen komponent) eller hvis noen klikket på elementet inneholder det aktuelle elementet (for eksempel våre div som omslutter vår meny og hamburger-ikonet). Hvis så, vi ikke gjør noe, ellers, vi kaller en funksjon, og at vi får navnet behandler.

Vi kommer til å bruke ref for å sjekke klikket element, og vi vil gjøre det hver gang noen klikker på siden.

// hooks.js
import { useEffect } fra “reagerer’;

eksport const useOnClickOutside = (ref, handler) => {
useEffect(() => {
const listener = event => {
if (!ref.nåværende || ref.gjeldende.inneholder(event.målet)) {
tilbake;
}
behandleren(event);
};
dokumentet.addEventListener(‘mousedown’, listener);
retur () => {
dokumentet.removeEventListener(‘mousedown’, listener);
};
},
[ref, behandler],
);
};

Ikke glem å returnere funksjon fra useEffect. Det er såkalte “rydde opp”, og i utgangspunktet, det står for å fjerne en hendelse som lytter når komponent unmounts. Det er utskifting av componentWillUnmount livssyklus.

La oss nå hekte kroken

Vi har fått vår kroken klar, så det er på tide å legge det til app. Gå til App.js fil, og importere to kroker: den nyopprettede useOnClickOutside og også useRef. Vi trenger sistnevnte for å få en referanse til element.

// App.js
import Reagere, { useState, useRef } fra “reagerer’;
import { useOnClickOutside } fra ‘./kroker’;

For å få tilgang til disse i det aktuelle elementet vi trenger for å få tilgang til DOM node. Det er der vi bruker useRef, også navnet på noden helt reflekterer poenget med denne variabelen.

Derfra passerer vi den noden som et første argument. Vi vil passere funksjon som lukkes vår meny som andre argument.

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

Til slutt, vi trenger for å passere vår ref til DOM-element. I vårt tilfelle, vil det være div, som holder Burger og Menyen komponenter:

// App.js
<div ref={node}>
<Burger open={åpne} setOpen={setOpen} />
<Meny for å åpne={åpne} setOpen={setOpen} />
</div>

Din App.js bør se ut som dette:

// App.js
import Reagere, { useState, useRef } fra “reagerer’;
import { ThemeProvider } fra ‘stylet-komponenter’;
import { useOnClickOutside } fra ‘./kroker’;
import { GlobalStyles } fra ‘./global’;
import { tema } fra ‘./tema’;
import { Burger, Meny } fra ‘./komponenter’;
funksjonen App() {
const [åpne, setOpen] = useState(false);
const node = useRef();
useOnClickOutside(node, () => setOpen(false));
retur (
<ThemeProvider tema={tema}>
<>
<GlobalStyles />
<div>
<h1>Hei. Dette er burger meny opplæringen</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animerte burger” />
</div>
<div ref={node}>
<Burger open={åpne} setOpen={setOpen} />
<Meny for å åpne={åpne} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
eksport-standard-App;

Sjekk ut dette! Det fungerer som forventet, og det er fullt funksjonell og responsiv.

Gratulerer, alle sammen! Du gjorde en flott jobb! Glad for koding!

Se på GitHub