Põhjalik juhend Reacti createPortal API kohta, mis käsitleb portaalide loomise tehnikaid, sündmuste käsitlemise strateegiaid ja täiustatud kasutusjuhtumeid paindlike ja ligipääsetavate kasutajaliideste loomiseks.
React createPortal: portaalide loomise ja sündmuste käsitlemise meisterklass
Tänapäevases Reactiga veebiarenduses on ülioluline luua kasutajaliideseid, mis integreeruvad sujuvalt aluseks oleva dokumendistruktuuriga. Kuigi Reacti komponendimudel on virtuaalse DOM-i haldamisel suurepärane, on meil mõnikord vaja renderdada elemente väljaspool tavapärast komponendihierarhiat. Siin tulebki appi createPortal. See juhend uurib createPortal'i põhjalikult, käsitledes selle eesmärki, kasutamist ja täiustatud tehnikaid sündmuste haldamiseks ja keerukate kasutajaliidese elementide loomiseks. Me käsitleme rahvusvahelistamise kaalutlusi, ligipääsetavuse parimaid tavasid ja levinumaid vigu, mida vältida.
Mis on React createPortal?
createPortal on Reacti API, mis võimaldab teil renderdada Reacti komponendi lapsi DOM-puu teise ossa, väljaspool vanemkomponendi hierarhiat. See on eriti kasulik selliste elementide loomiseks nagu modaalaknad, tööriistavihjed, rippmenüüd ja ülekattekihid, mis peavad asuma dokumendi ülatasemel või konkreetses konteineris, olenemata sellest, kus neid käivitav komponent Reacti komponendipuus asub.
Ilma createPortal'ita hõlmab selle saavutamine sageli keerulisi lahendusi, nagu DOM-i otsene manipuleerimine või CSS-i absoluutse positsioneerimise kasutamine, mis võib põhjustada probleeme virnastamiskontekstide, z-indeksi konfliktide ja ligipääsetavusega.
Miks kasutada createPortal'it?
Siin on peamised põhjused, miks createPortal on teie Reacti arsenalis väärtuslik tööriist:
- Parem DOM-struktuur: Väldib komponentide sügavat pesastamist DOM-is, mis viib puhtama ja paremini hallatava struktuurini. See on eriti oluline keerukate rakenduste puhul, millel on palju interaktiivseid elemente.
- Lihtsustatud stiilimine: Lihtne positsioneerida elemente vaateava või konkreetsete konteinerite suhtes, ilma et peaks tuginema keerukatele CSS-i nippidele. See lihtsustab stiilimist ja paigutust, eriti tegeledes elementidega, mis peavad katma muud sisu.
- Parem ligipääsetavus: Hõlbustab ligipääsetavate kasutajaliideste loomist, võimaldades teil hallata fookust ja klaviatuurinavigatsiooni komponendihierarhiast sõltumatult. Näiteks tagades, et fookus jääb modaalakna sisse.
- Parem sündmuste käsitlemine: Võimaldab sündmustel portaali sisust Reacti puusse korrektselt levida, tagades, et vanemkomponentidele lisatud sündmuste kuulajad töötavad endiselt ootuspäraselt.
createPortal'i põhikasutus
createPortal API aktsepteerib kahte argumenti:
- Reacti node (JSX), mida soovite renderdada.
- DOM-element, kuhu soovite node'i renderdada. See DOM-element peaks ideaalis eksisteerima enne, kui
createPortal'it kasutav komponent mountitakse.
Siin on lihtne näide:
Näide: Modaalakna renderdamine
Oletame, et teil on modaalkomponent, mida soovite renderdada body elemendi lõppu.
import React from 'react';
import ReactDOM from 'react-dom';
function Modal({ children, isOpen, onClose }) {
if (!isOpen) return null;
const modalRoot = document.getElementById('modal-root'); // Eeldab, et teil on HTML-is <div id="modal-root"></div>
if (!modalRoot) {
console.error('Modal root element not found!');
return null;
}
return ReactDOM.createPortal(
<div className="modal-overlay" onClick={onClose}>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
{children}
</div>
</div>,
modalRoot
);
}
export default Modal;
Selgitus:
- Me impordime
ReactDOM'i, sestcreatePortalonReactDOMobjekti meetod. - Eeldame, et teie HTML-is on olemas DOM-element ID-ga
modal-root. See on koht, kuhu modaalaken renderdatakse. Veenduge, et see element eksisteerib. Levinud tava on lisada<div id="modal-root"></div>vahetult enne sulgevat</body>silti omaindex.htmlfailis. - Kasutame
ReactDOM.createPortal'it, et renderdada modaalakna JSXmodalRootelemendi sisse. - Kasutame
e.stopPropagation(), et vältida modaalakna sisul olevaonClicksündmuse käivitamist ülekattekihil olevaleonClosekäsitlejale. See tagab, et modaalakna sees klõpsamine seda ei sulge.
Kasutamine:
import React, { useState } from 'react';
import Modal from './Modal';
function App() {
const [isModalOpen, setIsModalOpen] = useState(false);
return (
<div>
<button onClick={() => setIsModalOpen(true)}>Ava modaalaken</button>
<Modal isOpen={isModalOpen} onClose={() => setIsModalOpen(false)}>
<h2>Modaalakna sisu</h2>
<p>See on modaalakna sisu.</p>
<button onClick={() => setIsModalOpen(false)}>Sulge</button>
</Modal>
</div>
);
}
export default App;
See näide demonstreerib, kuidas renderdada modaalakent väljaspool tavapärast komponendihierarhiat, võimaldades teil seda lehel absoluutselt positsioneerida. createPortal'i selline kasutamine lahendab levinud probleeme virnastamiskontekstidega ja võimaldab teil hõlpsasti luua oma rakenduses ühtse stiiliga modaalaknaid.
Sündmuste käsitlemine createPortal'iga
Üks createPortal'i peamisi eeliseid on see, et see säilitab Reacti tavapärase sündmuste mullitamise käitumise. See tähendab, et portaali sisust pärinevad sündmused levivad endiselt ülespoole Reacti komponendipuud, võimaldades vanemkomponentidel neid käsitleda.
Siiski on oluline mõista, kuidas sündmusi käsitletakse, kui need ületavad portaali piiri.
Näide: Sündmuste käsitlemine väljaspool portaali
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function OutsideClickExample() {
const [isOpen, setIsOpen] = useState(false);
const dropdownRef = useRef(null);
const portalRoot = document.getElementById('portal-root');
useEffect(() => {
function handleClickOutside(event) {
if (dropdownRef.current && !dropdownRef.current.contains(event.target)) {
setIsOpen(false);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [dropdownRef]);
return (
<div>
<button onClick={() => setIsOpen(!isOpen)}>Lülita rippmenüü</button>
{isOpen && portalRoot && ReactDOM.createPortal(
<div ref={dropdownRef} style={{ position: 'absolute', top: '50px', left: '0', border: '1px solid black', padding: '10px', backgroundColor: 'white' }}>
Rippmenüü sisu
</div>,
portalRoot
)}
</div>
);
}
export default OutsideClickExample;
Selgitus:
- Kasutame
ref'i, et pääseda ligi portaali sees renderdatud rippmenüü elemendile. - Lisame
document'ilemousedownsündmuse kuulaja, et tuvastada klikke väljaspool rippmenüüd. - Sündmuse kuulaja sees kontrollime, kas klõps toimus väljaspool rippmenüüd, kasutades
dropdownRef.current.contains(event.target). - Kui klõps toimus väljaspool rippmenüüd, sulgeme selle, seades
isOpenväärtuseksfalse.
See näide demonstreerib, kuidas käsitleda sündmusi, mis toimuvad väljaspool portaali sisu, võimaldades teil luua interaktiivseid elemente, mis reageerivad kasutaja tegevustele ümbritsevas dokumendis.
Täiustatud kasutusjuhud
createPortal ei piirdu ainult lihtsate modaalakende ja tööriistavihjetega. Seda saab kasutada mitmesugustes täiustatud stsenaariumides, sealhulgas:
- Kontekstimenüüd: Dünaamiliselt renderdada kontekstimenüüsid hiirekursori lähedale paremklõpsul.
- Teated: Kuvada teateid ekraani ülaosas, sõltumata komponendihierarhiast.
- Kohandatud hüpikaknad: Luua kohandatud hüpikakna komponente täiustatud positsioneerimise ja stiilimisega.
- Integratsioon kolmandate osapoolte teekidega: Kasutada
createPortal'it Reacti komponentide integreerimiseks kolmandate osapoolte teekidega, mis nõuavad spetsiifilisi DOM-struktuure.
Näide: Kontekstimenüü loomine
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function ContextMenuExample() {
const [contextMenu, setContextMenu] = useState(null);
const menuRef = useRef(null);
useEffect(() => {
function handleClickOutside(event) {
if (menuRef.current && !menuRef.current.contains(event.target)) {
setContextMenu(null);
}
}
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [menuRef]);
const handleContextMenu = (event) => {
event.preventDefault();
setContextMenu({
x: event.clientX,
y: event.clientY,
});
};
const portalRoot = document.getElementById('portal-root');
return (
<div onContextMenu={handleContextMenu} style={{ border: '1px solid black', padding: '20px' }}>
Paremklõpsake siin, et avada kontekstimenüü
{contextMenu && portalRoot && ReactDOM.createPortal(
<div
ref={menuRef}
style={{
position: 'absolute',
top: contextMenu.y,
left: contextMenu.x,
border: '1px solid black',
padding: '10px',
backgroundColor: 'white',
}}
>
<ul>
<li>Valik 1</li>
<li>Valik 2</li>
<li>Valik 3</li>
</ul>
</div>,
portalRoot
)}
</div>
);
}
export default ContextMenuExample;
Selgitus:
- Kasutame
onContextMenusündmust, et tuvastada paremklõpse sihtelemendil. - Väldime vaikekontekstimenüü ilmumist, kasutades
event.preventDefault(). - Salvestame hiire koordinaadid
contextMenuolekumuutujasse. - Renderdame kontekstimenüü portaali sees, positsioneerituna hiire koordinaatidele.
- Kaasame sama väljaspool-klikki tuvastamise loogika nagu eelmises näites, et sulgeda kontekstimenüü, kui kasutaja klõpsab sellest väljaspool.
Ligipääsetavuse kaalutlused
createPortal'it kasutades on ülioluline arvestada ligipääsetavusega, et tagada teie rakenduse kasutatavus kõigi jaoks.
Fookuse haldamine
Kui portaal avaneb (nt modaalaken), peaksite tagama, et fookus liigutatakse automaatselt esimesele interaktiivsele elemendile portaali sees. See aitab kasutajatel, kes navigeerivad klaviatuuri või ekraanilugejaga, portaali sisule hõlpsasti juurde pääseda.
Kui portaal sulgub, peaksite fookuse tagastama elemendile, mis portaali avamise käivitas. See säilitab ühtse navigeerimisvoo.
ARIA atribuudid
Kasutage ARIA atribuute, et anda semantilist teavet portaali sisu kohta. Näiteks kasutage aria-modal="true" modaalelemendil, et näidata, et tegemist on modaaldialoogiga. Kasutage aria-labelledby, et seostada modaalaken selle pealkirjaga, ja aria-describedby, et seostada see selle kirjeldusega.
Klaviatuurinavigatsioon
Veenduge, et kasutajad saaksid portaali sisus navigeerida klaviatuuri abil. Kasutage tabindex atribuuti fookuse järjekorra kontrollimiseks ja veenduge, et kõik interaktiivsed elemendid on klaviatuuriga ligipääsetavad.
Kaaluge fookuse püüdmist portaali sisse, et kasutajad ei saaks kogemata sellest väljapoole navigeerida. Seda saab saavutada, kuulates Tab klahvi ja liigutades fookuse programmiliselt esimesele või viimasele interaktiivsele elemendile portaali sees.
Näide: Ligipääsetav modaalaken
import React, { useState, useRef, useEffect } from 'react';
import ReactDOM from 'react-dom';
function AccessibleModal({ children, isOpen, onClose, labelledBy, describedBy }) {
const modalRef = useRef(null);
const firstFocusableElementRef = useRef(null);
const [previouslyFocusedElement, setPreviouslyFocusedElement] = useState(null);
const modalRoot = document.getElementById('modal-root');
useEffect(() => {
if (isOpen) {
// Salvesta hetkel fookuses olev element enne modaalakna avamist.
setPreviouslyFocusedElement(document.activeElement);
// Vii fookus esimesele fookustatavale elemendile modaalaknas.
if (firstFocusableElementRef.current) {
firstFocusableElementRef.current.focus();
}
// Püüa fookus modaalakna sisse.
function handleKeyDown(event) {
if (event.key === 'Tab') {
const focusableElements = modalRef.current.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstFocusableElement = focusableElements[0];
const lastFocusableElement = focusableElements[focusableElements.length - 1];
if (event.shiftKey) {
// Shift + Tab
if (document.activeElement === firstFocusableElement) {
lastFocusableElement.focus();
event.preventDefault();
}
} else {
// Tab
if (document.activeElement === lastFocusableElement) {
firstFocusableElement.focus();
event.preventDefault();
}
}
}
}
document.addEventListener('keydown', handleKeyDown);
return () => {
document.removeEventListener('keydown', handleKeyDown);
// Taasta fookus elemendile, mis oli fookuses enne modaalakna avamist.
if(previouslyFocusedElement && previouslyFocusedElement.focus) {
previouslyFocusedElement.focus();
}
};
}
}, [isOpen, previouslyFocusedElement]);
if (!isOpen) return null;
return ReactDOM.createPortal(
<div
className="modal-overlay"
onClick={onClose}
aria-modal="true"
aria-labelledby={labelledBy}
aria-describedby={describedBy}
ref={modalRef}
>
<div className="modal-content" onClick={(e) => e.stopPropagation()}>
<h2 id={labelledBy}>Modaalakna pealkiri</h2>
<p id={describedBy}>See on modaalakna sisu.</p>
<button ref={firstFocusableElementRef} onClick={onClose}>
Sulge
</button>
{children}
</div>
</div>,
modalRoot
);
}
export default AccessibleModal;
Selgitus:
- Kasutame ARIA atribuute nagu
aria-modal,aria-labelledbyjaaria-describedby, et anda modaalakna kohta semantilist teavet. - Kasutame
useEffecthook'i fookuse haldamiseks, kui modaalaken avaneb ja sulgub. - Salvestame hetkel fookuses oleva elemendi enne modaalakna avamist ja taastame fookuse sellele, kui modaalaken sulgub.
- Püüame fookuse modaalakna sisse, kasutades
keydownsündmuse kuulajat.
Rahvusvahelistamise (i18n) kaalutlused
Globaalsele publikule rakenduste arendamisel on rahvusvahelistamine (i18n) kriitilise tähtsusega kaalutlus. createPortal'it kasutades tuleb meeles pidada mõningaid punkte:
- Teksti suund (RTL/LTR): Veenduge, et teie stiilid toetavad nii vasakult-paremale (LTR) kui ka paremalt-vasakule (RTL) keeli. See võib hõlmata loogiliste omaduste kasutamist CSS-is (nt
margin-inline-startasemelmargin-left) jadiratribuudi sobivat seadistamist HTML-elemendil. - Sisu lokaliseerimine: Kogu portaali sisu tuleks lokaliseerida vastavalt kasutaja eelistatud keelele. Kasutage tõlgete haldamiseks i18n teeki (nt
react-intl,i18next). - Numbrite ja kuupäevade vormindamine: Vormindage numbrid ja kuupäevad vastavalt kasutaja lokaadile.
IntlAPI pakub selleks funktsionaalsust. - Kultuurilised tavad: Olge teadlik kultuurilistest tavadest, mis on seotud kasutajaliidese elementidega. Näiteks võib nuppude paigutus kultuuriti erineda.
Näide: i18n koos react-intl'iga
import React from 'react';
import { FormattedMessage } from 'react-intl';
function MyComponent() {
return (
<div>
<FormattedMessage id="myComponent.greeting" defaultMessage="Hello, world!" />
</div>
);
}
export default MyComponent;
FormattedMessage komponent react-intl'ist hangib tõlgitud sõnumi vastavalt kasutaja lokaadile. Konfigureerige react-intl oma tõlgetega erinevate keelte jaoks.
Levinud lõksud ja lahendused
Kuigi createPortal on võimas tööriist, on oluline olla teadlik mõningatest levinud lõksudest ja kuidas neid vältida:
- Puuduv portaali juurelement: Veenduge, et DOM-element, mida kasutate portaali juurena, eksisteerib enne, kui
createPortal'it kasutav komponent mountitakse. Hea tava on paigutada see otseindex.htmlfaili. - Z-indeksi konfliktid: Olge
createPortal'iga elemente positsioneerides teadlik z-indeksi väärtustest. Kasutage CSS-i virnastamiskontekstide haldamiseks ja veenduge, et teie portaali sisu kuvatakse korrektselt. - Sündmuste käsitlemise probleemid: Mõistke, kuidas sündmused läbi portaali levivad ja käsitlege neid asjakohaselt. Kasutage
e.stopPropagation(), et vältida sündmuste soovimatute tegevuste käivitamist. - Mälulekked: Koristage sündmuste kuulajad ja viited korralikult ära, kui
createPortal'it kasutav komponent unmountitakse, et vältida mälulekkeid. Kasutage selleksuseEffecthook'i koos puhastusfunktsiooniga. - Ootamatud kerimisprobleemid: Portaalid võivad mõnikord häirida lehe oodatud kerimiskäitumist. Veenduge, et teie stiilid ei takista kerimist ja et modaalelemendid ei põhjusta lehe hüppamist ega ootamatut kerimiskäitumist, kui need avanevad ja sulguvad.
Kokkuvõte
React.createPortal on väärtuslik tööriist paindlike, ligipääsetavate ja hooldatavate kasutajaliideste loomiseks Reactis. Mõistes selle eesmärki, kasutamist ja täiustatud tehnikaid sündmuste ja ligipääsetavuse käsitlemiseks, saate selle võimsust ära kasutada keerukate ja kaasahaaravate veebirakenduste loomiseks, mis pakuvad suurepärast kasutajakogemust globaalsele publikule. Ärge unustage arvestada rahvusvahelistamise ja ligipääsetavuse parimate tavadega, et tagada teie rakenduste kaasavus ja kasutatavus kõigi jaoks.
Järgides selles juhendis toodud juhiseid ja näiteid, saate enesekindlalt kasutada createPortal'it levinud kasutajaliidese väljakutsete lahendamiseks ja vapustavate veebikogemuste loomiseks.