Hamburger Menu met een Zijde van Reageren Haken en Gestyled Onderdelen

0
8

We weten allemaal wat een hamburger menu is rechts? Wanneer het patroon begonnen met het maken van zijn weg in het web designs, het was bespot en toegejuicht voor haar minimalisme waarmee hoofdmenu ‘ s worden weggestopt off-screen, met name op mobiele waarbij elke pixel van de ruimte telt.

CSS-Tricks is al ongeveer het dubbele van het vlees.

Love ’em or hate ’em, hamburger menu’ s zijn hier en waarschijnlijk zal het voor enige tijd te komen. Het probleem is hoe om ze te implementeren. Zeker, ze zien er eenvoudig en duidelijk, maar ze kan van alles zijn, maar. Bijvoorbeeld, indien ze worden gecombineerd met een label? Zijn ze effectiever op de linker-of rechterkant van het scherm? Hoe pakken we sluiten deze menu ‘ s, of door te klikken of aan te raken? Moet het pictogram van een SVG, het lettertype Unicode-teken, of pure CSS? Wat te denken van een vleesloos optie?

Ik wilde om één van die, maar faalde in het vinden van een eenvoudige oplossing. De meeste oplossingen zijn gebaseerd op de bibliotheken, zoals reactjs-pop-up of reageren-hamburger-menu. Ze zijn geweldig, maar voor meer complexe oplossingen. Hoe zit het met de kern gebruiken geval van een drie-line menu dat gewoon schuift een paneel uit de zijkant van het scherm wanneer erop wordt geklikt, dan schuift het paneel terug in wanneer erop wordt geklikt weer?

Ik besloot tot de bouw van mijn eigen eenvoudige hamburger met zijbalk. Geen augurken, uien en ketchup. Alleen het vlees, broodje, en een kant van menu-items.

Bent u klaar om het te maken met mij?

Bekijk op CodePen Uitzicht op GitHub

Hier is wat we maken

Zie de Pen
Hamburger menu met Reageren haken en stijl-onderdelen van Maks Akymenko (@maximakymenko)
op CodePen.

We bouwen Reageren gebruik voor deze tutorial, want het lijkt een goed use case voor het: we krijgen een herbruikbare component en een set haken we kunnen uitbreiden tot het verwerken van de op functionaliteit.

Spin tot een nieuwe Reageren project

Laat draaien tot een nieuw project gebruik van maken-reageren-app, naar die map en voeg stijl-componenten voor de stijl van de GEBRUIKERSINTERFACE:

npx maken-reageren-app-je-project-naam
cd-uw-project-naam
garen voeg stijl-onderdelen

Toevoegen basic stijlen

Open de zojuist gemaakte project in uw favoriete code-editor en start met het toevoegen van basic stijlen met stijl-onderdelen. In uw src map maken een bestand genaamd global.js. Het zal bevatten stijlen voor het hele app. U kunt uw eigen of gewoon kopiëren wat ik deed:

// global.js
importeren { createGlobalStyle } van de ‘stijl-onderdelen’;

export const GlobalStyles = createGlobalStyle`
html, body {
margin: 0;
padding: 0;
}
*, *::na, *::before {
box-sizing: border-box;
}
body {
lijn-items: center;
achtergrond: #0D0C1D;
color: #EFFFFA;
display: flex;
font-family: -apple-systeem, BlinkMacSystemFont, “Segoe UI”, Roboto, Helvetica, Arial, sans-serif, “Apple Kleur Emoji”, “Segoe UI Emoji”, “Segoe UI Symbol”;
hoogte: 100vh;
rechtvaardiging-inhoud: center;
tekst-rendering: optimizeLegibility;
}
`

Dit is slechts een gedeelte van de globale stijlen, de rest kunt u hier vinden.

De CreateGlobalStyle functie wordt over het algemeen gebruikt voor het maken van globale stijlen die zijn blootgesteld aan de hele app. We importeren, zodat wij toegang hebben tot deze stijlen als we gaan.

De volgende stap is het toevoegen van een thema-bestand waarin al onze variabelen. Het maken van een theme.js bestand in de map src en voeg volgende:

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

Toevoegen lay-out, het menu en de hamburger onderdelen 🍔

Ga naar uw App.js -bestand. We gaan vegen alles uit te maken van de main template voor onze app. Hier is wat ik deed. U kunt wel uw eigen maken.

// App.js
importeren Reageren van ‘reageren’;
importeren { ThemeProvider } van de ‘stijl-onderdelen’;
importeren { GlobalStyles } uit ‘./globaal’;
importeren { thema } uit ‘./thema’;

functie-App() {
return (
<ThemeProvider thema={thema}>
<>
<GlobalStyles />
<div>
<h1>Hallo. Dit is hamburger menu tutorial</h1>
<img src=”https://image.flaticon.com/icons/svg/2016/2016012.svg” alt=”burger icon” />
<small>Pictogram gemaakt door Freepik van www.flaticon.com</small>
</div>
</>
</ThemeProvider>
);
}
export standaard applicatie;

Niet vergeten toe te voegen de lijn met de kleine tag. Dat is hoe we het credit flaticon.comhttp://flaticon.com) auteurs voor de geleverde pictogram.

Hier is wat we hebben tot op dit punt:

Laat het me uitleggen een beetje. We geïmporteerd ThemeProvider, dat is een wrapper component die gebruik maakt van de Context API achter de schermen om onze thema variabelen die beschikbaar zijn op het hele onderdeel van boom.

We hebben ook geïmporteerd onze GlobalStyles en gaf ze als een onderdeel van onze app, wat betekent dat onze applicatie heeft nu toegang tot alle globale stijlen. Zoals u kunt zien, is onze GlobalStyles component is binnen ThemeProvider dat betekent dat we kunnen nu al enkele kleine aanpassingen in de it.

Ga naar global.js en het veranderen van de achtergrond kleur en eigenschappen gebruik te maken van onze gedefinieerde variabelen. Dit helpt ons bij het implementeren van een thema in plaats van het gebruik van vaste waarden die zijn moeilijk te veranderen.

// global.js
achtergrond: ${({ thema }) => thema.primaryDark};
kleur: ${({ thema }) => thema.primaryLight};

We destructure onze thema van rekwisieten. Dus, in plaats van het schrijven van rekwisieten.het thema elk moment gebruiken we een hoop haken voor in de plaats. Ik herhaal mezelf: het thema is beschikbaar, omdat we hebben gewikkeld onze globale stijlen met ThemeProvider.

Maak Burger en Menu-onderdelen

Maak een map componenten in de src map en voeg twee mappen in er: het Menu en de Burger, plus een index.js -bestand.

index.js zal worden gebruikt voor een doel: laat ons het importeren van onderdelen van een bestand, dat is erg handig, vooral als je veel van hen.

Nu maken we onze componenten. Elke map bevat drie bestanden.

Wat is er met alle bestanden? Zie je het voordeel van een schaalbare structuur snel genoeg. Het werkte goed voor mij in een paar projecten, maar hier is een goed advies, het maken van schaalbare structuur.

Ga naar de Burger map maken Burger.js voor onze lay-out. Voeg vervolgens Burger.styled.js bevat stijlen, en index.js. die zal het exporteren van het bestand.

// index.js
export { default } uit ‘./Burger’;

Voel je vrij om de stijl van de burger schakelen op een manier die u wilt, of plak de volgende stijlen:

// Burger.styled.js
importeer stijl van ‘stijl-onderdelen’;

export const StyledBurger = gestyled.knop`
position: absolute;
top: 5%;
links: 2rem;
display: flex;
flex-richting: kolom;
rechtvaardiging-inhoud: in de ruimte rond;
breedte: 2rem;
hoogte: 2rem;
achtergrond: transparant;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;

&:focus {
outline: none;
}

div {
breedte: 2rem;
hoogte: 0.25 rem;
achtergrond: ${({ thema }) => thema.primaryLight};
border-radius: 10px;
overgang: alle 0.3 s lineair;
position: relative;
transform-herkomst: 1px;
}
`;

De transformatie is van oorsprong eigendom later nodig zullen zijn om te animeren het menu wisselt tussen open en gesloten staten.

Na het toevoegen van de stijlen, ga naar Burger.js en voeg de lay-out:

// Burger.js
importeren Reageren van ‘reageren’;
importeren { StyledBurger } uit ‘./Hamburger.stijl’;

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

export standaard Burger;

Kijk daarna op de linker bovenhoek. Ziet u het?

Tijd om te doen hetzelfde met de map in het Menu:

// Menu -> index.js
export { default } uit ‘./Menu’;

// Menu.styled.js
importeer stijl van ‘stijl-onderdelen’;

export const StyledMenu = gestyled.nav`
display: flex;
flex-richting: kolom;
rechtvaardiging-inhoud: center;
achtergrond: ${({ thema }) => thema.primaryLight};
hoogte: 100vh;
text-align: left;
padding: 2rem;
position: absolute;
top: 0;
links: 0;
overgang: de transformatie van 0,3 s gemak-in-out;

@media (max-width: ${({ thema }) => thema.mobiele}) {
breedte: 100%;
}

een {
font-size: 2rem;
text-transform: uppercase;
padding: 2rem 0;
font-weight: bold;
letter-spacing: 0.5 rem;
kleur: ${({ thema }) => thema.primaryDark};
text-decoration: none;
overgang: kleur 0,3 s lineair;

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

&:hover {
kleur: ${({ thema }) => thema.primaryHover};
}
}
`;

Laten we vervolgens toe te voegen in de lay-out voor de menu-items die verschijnen bij het klikken op onze hamburger:

// Menu.js
importeren Reageren van ‘reageren’;
importeren { StyledMenu } uit ‘./- Menu.stijl’;

const Menu = () => {
return (
<StyledMenu>
<a href=”/”>
<span role=”img” aria-label=”over ons”>&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Over ons
</een>
<a href=”/”>
<span role=”img” aria-label=”prijs”>&#x1f4b8;</span>
Prijzen
</een>
<a href=”/”>
<span role=”img” aria-label=”contact”>&#x1f4e9;</span>
Contact
</een>
</StyledMenu>
)
}
export standaard Menu;

We hebben mooie emojis hier, en de beste praktijk is om ze toegankelijk te maken door het te verpakken elk in een span en het toevoegen van een paar eigenschappen: role=”img” en aria-label=”etiket”. U kunt meer lezen over het hier.

Tijd om te importeren onze nieuwe onderdelen in onze App.js bestand:

// App.js
importeren Reageren van ‘reageren’;
importeren { ThemeProvider } van de ‘stijl-onderdelen’;
importeren { GlobalStyles } uit ‘./globaal’;
importeren { thema } uit ‘./thema’;
importeren { Burger, Menu } uit ‘./componenten’;

// …

Laten we eens kijken, wat hebben we:

Neem een kijkje op deze mooie navigatiebalk! Maar we hebben een probleem hier: het geopend is, en we willen het in eerste instantie te worden gesloten. We hoeven alleen maar het toevoegen van een regel aan Menu.styled.js fix:

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

We zijn goed op weg naar het aanroepen van deze burger gekookt! Maar eerst…

Het toevoegen van openen en sluiten functionaliteit

We willen de zijbalk openen bij het klikken op de hamburger pictogram, dus laten we het maar door gaan. Open App.js en voeg wat staat er. We zullen gebruik maken van de useState haak voor.

// App.js
importeren Reageren, { useState } van ‘reageren’;

Na het importeren van het, laten we het gebruiken in de App component.

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

We stellen de oorspronkelijke staat is onwaar, omdat ons menu zouden moeten worden verborgen wanneer de toepassing wordt weergegeven.

Wij moeten onze in-en uitschakelen en zijbalk menu te weten over de staat, dus geef het af als een prop op elk onderdeel. Nu uw App.js moet er als volgt uitzien:

// App.js
importeren Reageren, { useState } van ‘reageren’;
importeren { ThemeProvider } van de ‘stijl-onderdelen’;
importeren { GlobalStyles } uit ‘./globaal’;
importeren { thema } uit ‘./thema’;
importeren { Burger, Menu } uit ‘./componenten’;

functie-App() {
const [open, setOpen] = useState(false);
return (
<ThemeProvider thema={thema}>
<>
<GlobalStyles />
<div>
<h1>Hallo. Dit is hamburger menu tutorial</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animated burger” />
</div>
<div>
<Hamburger open={open} setOpen={setOpen} />
<Menu open={open} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
export standaard applicatie;

Merk op dat we verpakken onze producten in een div. Dit zal nuttig zijn later, toen we functionaliteit toe te voegen die hiermee sluit u het menu bij het klikken op een willekeurige plaats op het scherm.

Handvat rekwisieten in de onderdelen

Onze Hamburger Menu weten over de staat, dus het enige dat we moeten doen is voor het verwerken van het binnen en het toevoegen van stijlen dienovereenkomstig. Ga naar Burger.js en het verwerken van de attributen die werden doorgegeven:

// Burger.js
importeren Reageren van ‘reageren’;
importeren { bool, func } van de ‘prop-types’;
importeren { StyledBurger } uit ‘./Hamburger.stijl’;
const Burger = ({ open, setOpen }) => {
return (
<StyledBurger open={open} onClick={() => setOpen(!open)}>
<div />
<div />
<div />
</StyledBurger>
)
}
Hamburger.propTypes = {
open: bool.isRequired,
setOpen: func.isRequired,
};
export standaard Burger;

We destructure de open en setOpen rekwisieten en ze doorgeven aan onze StyledBurger toevoegen stijlen voor elke prop, respectievelijk. Ook voegen we de onClick-handler te bellen met onze setOpen functie en stelt open prop. Aan het eind van het bestand voegen we het type controle, die wordt beschouwd als een best practice voor het uitlijnen van argumenten met de verwachte gegevens.

U kunt controleren of het werkt of niet door te gaan naar uw reageren-dev-tools. Ga naar het tabblad Onderdelen in uw Chrome DevTools en klik op de Burger tabblad.

Nu, wanneer u klikt op uw Hamburger component, (don ‘ t mix it up met het tabblad), moet je zien, dat je open selectievakje is het veranderen van de staat.

Ga naar Menu.js en doen bijna hetzelfde, hoewel, hier passeren we alleen de open prop:

// Menu.js
importeren Reageren van ‘reageren’;
importeren { bool } van de ‘prop-types’;
importeren { StyledMenu } uit ‘./- Menu.stijl’;
const Menu = ({ open }) => {
return (
<StyledMenu open={open}>
<a href=”/”>
<span role=”img” aria-label=”over ons”>&#x1f481;&#x1f3fb;&#x200d;&#x2642;&#xfe0f;</span>
Over ons
</een>
<a href=”/”>
<span role=”img” aria-label=”prijs”>&#x1f4b8;</span>
Prijzen
</een>
<a href=”/”>
<span role=”img” aria-label=”contact”>&#x1f4e9;</span>
Contact
</een>
</StyledMenu>
)
}
– Menu.propTypes = {
open: bool.isRequired,
}
export standaard Menu;

De volgende stap is om open prop naar onze stijl component zodat we het kunnen toepassen van de overgang. Open Menu.styled.js en het volgende toevoegen aan onze transform-eigenschap:

transformeren: ${({ open }) => open ? ‘translateX(0)’ : ‘translateX(-100%)’};

Dit is om te controleren of onze stijl onderdeel prop is waar, en als dat zo is, voegt translateX(0) verplaatsen van onze navigatie op het scherm. U kunt al testen het uit in de buurt!

Wacht, wacht, wacht!

Heb je iets fout bij het controleren van dingen uit? Onze Burger heeft dezelfde kleur als de achtergrond van onze Menu ‘ s, waardoor ze in elkaar overlopen. Dat gaan we veranderen en ook geanimeerd pictogram een beetje om het interessanter te maken. We hebben de open prop doorgegeven, zodat wij die gebruiken kunt om de wijzigingen toe te passen.

Open Burger.styled.js en het volgende schrijven:

// Burger.styled.js
importeer stijl van ‘stijl-onderdelen’;
export const StyledBurger = gestyled.knop`
position: absolute;
top: 5%;
links: 2rem;
display: flex;
flex-richting: kolom;
rechtvaardiging-inhoud: in de ruimte rond;
breedte: 2rem;
hoogte: 2rem;
achtergrond: transparant;
border: none;
cursor: pointer;
padding: 0;
z-index: 10;

&:focus {
outline: none;
}

div {
breedte: 2rem;
hoogte: 0.25 rem;
achtergrond: ${({ theme, open }) => open ? – thema.primaryDark : thema.primaryLight};
border-radius: 10px;
overgang: alle 0.3 s lineair;
position: relative;
transform-herkomst: 1px;

:first-child {
transformeren: ${({ open }) => open ? ‘roteren(45deg)’ : ‘roteren(0)’};
}

:nth-child(2) {
dekking: ${({ open }) => open ? ‘0’ : ‘1’};
transformeren: ${({ open }) => open ? ‘translateX(20px)’ : ‘translateX(0)’};
}

:nth-child(3) {
transformeren: ${({ open }) => open ? ‘draaien(-45deg)’ : ‘roteren(0)’};
}
}
`;

Dit is een groot stuk van CSS, maar het maakt de animatie magie gebeuren. Wij controleren of de open prop is waar en stijlen te wijzigen dienovereenkomstig. We draaien, te vertalen, dan is het verbergen van het menu op het pictogram van de lijnen tijdens het wijzigen van de kleur. Mooi, niet?

Oke, mensen! Door nu, moet u weten hoe u een eenvoudige hamburger pictogram en menu, dat staat voor respons en vloeiende animaties. Van harte gefeliciteerd!

Maar er is nog een laatste ding moeten we rekening voor…

Sluit het menu door te klikken op de buitenwereld

Dit deel lijkt een kleine bonus, maar het is een groot UX winnen, omdat het laat de gebruiker toe om het menu te sluiten door te klikken op een andere plek op de pagina. Dit helpt de gebruiker niet hoeft te re-zoek het pictogram van het menu en te klikken op precies op.

We gaan meer Reageren haken om gebruik te maken van dit gebeuren! Maak een bestand aan in de map src, genoemd hooks.js en open het. Voor deze ene, we gaan het de beurt aan de useEffect haak, die werd geïntroduceerd in Reageren 18.

// hooks.js
importeren { useEffect } van ‘reageren’;

Voordat we het schrijven van de code, laten we eens nadenken over de logica achter deze haak. Wanneer we je klikt ergens op de pagina, moeten we controleren of het aangeklikte element is van onze huidige element (in ons geval, dat is het Menu-onderdeel) of als het aangeklikte element bevat van het huidige element (bijvoorbeeld, onze div die loopt van onze menu ‘ s en de hamburger-icoon). Als dat zo is, doen we niks, anders noemen we een functie, die we de naam van de handler.

We gaan gebruiken ref controleren van het aangeklikte element, en we doen dat elke keer dat iemand klikt op de pagina.

// hooks.js
importeren { useEffect } van ‘reageren’;

export const useOnClickOutside = (ref, handler) => {
useEffect(() => {
const luisteraar = event => {
if (!ref.huidige || ref.de huidige.bevat(event.het doel)) {
return;
}
de handler(evenement);
};
document.addEventListener(‘mousedown’, luisteraar);
return () => {
document.removeEventListener(‘mousedown’, luisteraar);
};
},
[ref, handler],
);
};

Vergeet niet om terug te keren de functie van useEffect. Dat is de zogenaamde “clean up” en, in principe, het staat voor het verwijderen van een event-listener wanneer de component hiermee ontkoppelt. Het is de vervanging van componentWillUnmount levenscyclus.

Laten we nu haak de haak

We hebben onze haak klaar, dus het is tijd om het toe te voegen aan de app. Ga naar de App.js bestand en importeer twee haken: de nieuw gecreëerde useOnClickOutside en ook useRef. We hebben de laatste is een verwijzing naar het element.

// App.js
importeren Reageren, { useState, useRef } van ‘reageren’;
importeren { useOnClickOutside } uit ‘./haken’;

Om toegang te krijgen tot deze in de huidige element dat we nodig hebben om toegang te krijgen tot de DOM knooppunt. Dat is waar wij gebruiken useRef, ook de naam van het knooppunt weerspiegelt perfect de punt van deze variabele.

Van daar zijn, passeren we de node als het eerste argument. We passeren de functie sluit het menu als een tweede argument.

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

Ten slotte moeten we onze ref naar de DOM-element. In ons geval is, zal de div, die in het bezit is van de Burger en Menu-onderdelen:

// App.js
<div ref={node}>
<Hamburger open={open} setOpen={setOpen} />
<Menu open={open} setOpen={setOpen} />
</div>

Uw App.js moet er ongeveer zo uitzien:

// App.js
importeren Reageren, { useState, useRef } van ‘reageren’;
importeren { ThemeProvider } van de ‘stijl-onderdelen’;
importeren { useOnClickOutside } uit ‘./haken’;
importeren { GlobalStyles } uit ‘./globaal’;
importeren { thema } uit ‘./thema’;
importeren { Burger, Menu } uit ‘./componenten’;
functie-App() {
const [open, setOpen] = useState(false);
const node = useRef();
useOnClickOutside(node () => setOpen(false));
return (
<ThemeProvider thema={thema}>
<>
<GlobalStyles />
<div>
<h1>Hallo. Dit is hamburger menu tutorial</h1>
<img src=”https://media.giphy.com/media/xTiTnwj1LUAw0RAfiU/giphy.gif” alt=”animated burger” />
</div>
<div ref={node}>
<Hamburger open={open} setOpen={setOpen} />
<Menu open={open} setOpen={setOpen} />
</div>
</>
</ThemeProvider>
);
}
export standaard applicatie;

Check dit uit! Het werkt zoals verwacht, en het is volledig functioneel en wendbaar.

Gefeliciteerd iedereen! U heeft een geweldige job! Gelukkig codering!

Bekijk op GitHub