Põhjalik juhend JavaScripti ResizeObserver API kohta, mis võimaldab luua tõeliselt reageerivaid, elemenditeadlikke komponente ja hallata dünaamilisi paigutusi suure jõudlusega.
ResizeObserver API: kaasaegse veebi saladus elemendi suuruse vaevatuks jälgimiseks ja reageerivateks paigutusteks
Kaasaegse veebiarenduse maailmas ehitame rakendusi komponentidest. Mõtleme iseseisvate, korduvkasutatavate kasutajaliidese plokkidena – kaardid, armatuurlauad, vidinad ja külgribad. Ometi on aastaid olnud meie peamine tööriist reageeriva disaini jaoks, CSS-i meediapäringud, põhimõtteliselt sellest komponendipõhisest reaalsusest lahti ühendatud. Meediapäringud hoolivad ainult ühest asjast: globaalse vaateakna suurusest. See piirang on sundinud arendajaid nurka, põhjustades keerulisi arvutusi, hapraid paigutusi ja ebatõhusaid JavaScripti häkke.
Mis siis, kui komponent võiks olla teadlik oma enda suurusest? Mis siis, kui see suudaks oma paigutust kohandada mitte sellepärast, et brauseri akna suurust muudeti, vaid sellepärast, et konteinerit, milles see asub, surus kokku naaberelement? See on probleem, mille ResizeObserver API elegantselt lahendab. See pakub jõudsat, usaldusväärset ja natiivset brauseri mehhanismi, et reageerida mis tahes DOM-elemendi suuruse muutustele, juhatades sisse tõelise elemenditaseme reageerivuse ajastu.
See põhjalik juhend uurib ResizeObserver API-t algusest peale. Me käsitleme, mis see on, miks see on monumentaalne edasiminek võrreldes varasemate meetoditega ja kuidas seda kasutada praktiliste, reaalsete näidete kaudu. Lõpuks olete varustatud, et ehitada robustsemaid, modulaarsemaid ja dünaamilisemaid paigutusi kui kunagi varem.
Vana viis: vaateaknapõhise reageerivuse piirangud
Et täielikult hinnata ResizeObserveri võimsust, peame esmalt mõistma väljakutseid, mida see ületab. Üle kümne aasta on meie reageeriva disaini tööriistakasti domineerinud kaks lähenemist: CSS-i meediapäringud ja JavaScriptipõhine sündmuste kuulamine.
CSS-i meediapäringute sundsärk
CSS-i meediapäringud on reageeriva veebidisaini nurgakivi. Need võimaldavad meil rakendada erinevaid stiile vastavalt seadme omadustele, kõige sagedamini vaateakna laiusele ja kõrgusele.
Tüüpiline meediapäring näeb välja selline:
/* Kui brauseri aken on 600px lai või vähem, muuda body taust helesiniseks */
@media screen and (max-width: 600px) {
body {
background-color: lightblue;
}
}
See töötab suurepäraselt kõrgetasemeliste lehepaigutuse kohanduste jaoks. Aga kaaluge korduvkasutatavat `UserInfo` kaardikomponenti. Võib-olla soovite, et see kaart kuvaks laias paigutuses avatari kasutaja nime kõrval, aga kitsas paigutuses paigutaks avatari nime peale. Kui see kaart paigutatakse laia põhisisu alasse, peaks see kasutama laia paigutust. Kui täpselt sama kaart paigutatakse kitsasse külgribasse, peaks see automaatselt kasutusele võtma kitsa paigutuse, sõltumata kogu vaateakna laiusest.
Meediapäringutega on see võimatu. Kaardil puudub teadmine oma kontekstist. Selle stiili dikteerib täielikult globaalne vaateaken. See sunnib arendajaid looma variandiklasse nagu .user-card--narrow
ja neid käsitsi rakendama, rikkudes komponendi iseseisvat olemust.
JavaScripti häkkide jõudluslõksud
Arendajate jaoks oli selle probleemi ees seistes loomulik järgmine samm pöörduda JavaScripti poole. Kõige tavalisem lähenemine oli kuulata `window` objekti `resize` sündmust.
window.addEventListener('resize', () => {
// Iga komponendi jaoks lehel, mis peab olema reageeriv...
// Hangi selle praegune laius
// Kontrolli, kas see ületab lävendi
// Rakenda klass või muuda stiile
});
Sellel lähenemisel on mitu kriitilist viga:
- Jõudluse õudusunenägu: `resize` sündmus võib ühe lohistamisega suuruse muutmise operatsiooni ajal käivituda kümneid või isegi sadu kordi. Kui teie käsitlejafunktsioon teostab keerulisi arvutusi või DOM-manipulatsioone mitme elemendi jaoks, võite kergesti põhjustada tõsiseid jõudlusprobleeme, hangumist ja paigutuse rabelemist.
- Endiselt vaateaknast sõltuv: Sündmus on seotud `window` objektiga, mitte elemendi endaga. Teie komponent muutub endiselt ainult siis, kui kogu aken suurust muudab, mitte siis, kui selle vanemkonteiner muutub muudel põhjustel (nt naaberelemendi lisamine, akordioni laienemine jne).
- Ebatõhus pollimine: Et püüda kinni suuruse muutusi, mida ei põhjustanud akna suuruse muutmine, kasutasid arendajad `setInterval` või `requestAnimationFrame` tsükleid, et perioodiliselt kontrollida elemendi mõõtmeid. See on äärmiselt ebatõhus, tarbides pidevalt protsessori tsükleid ja tühjendades mobiilseadmete akut, isegi kui midagi не muutub.
Need meetodid olid möödahiilimised, mitte lahendused. Veeb vajas paremat viisi – tõhusat, elemendikeskset API-t suuruse muutuste jälgimiseks. Ja see on täpselt see, mida ResizeObserver pakub.
Siseneb ResizeObserver: kaasaegne ja jõudluskeskne lahendus
Mis on ResizeObserver API?
ResizeObserver API on brauseri liides, mis võimaldab teil saada teate, kui elemendi sisu- või piirjoone kasti suurus muutub. See pakub asünkroonset ja jõudluskeskset viisi elementide suuruse muutuste jälgimiseks ilma käsitsi pollimise või `window.resize` sündmuse puudusteta.
Mõelge sellest kui `IntersectionObserver`-ist mõõtmete jaoks. Selle asemel, et öelda teile, millal element vaatevälja kerib, ütleb see teile, millal selle kasti suurust on muudetud. See võib juhtuda mitmel põhjusel:
- Brauseri akna suurust muudetakse.
- Sisu lisatakse elemendile või eemaldatakse sealt (nt tekst murdub uuele reale).
- Elemendi CSS-i omadusi nagu `width`, `height`, `padding` või `font-size` muudetakse.
- Elemendi vanema suurus muutub, põhjustades selle kahanemist või kasvamist.
Peamised eelised traditsiooniliste meetodite ees
ResizeObserver ei ole lihtsalt väike täiustus; see on paradigma muutus komponenditaseme paigutuse haldamisel.
- Väga jõudluskeskne: API on brauseri poolt optimeeritud. See ei käivita tagasikutset iga üksiku piksli muutuse kohta. Selle asemel koondab see teated ja edastab need tõhusalt brauseri renderdustsükli sees (tavaliselt vahetult enne värvimist), vältides paigutuse rabelemist, mis vaevab `window.resize` käsitlejaid.
- Elemendispetsiifiline: See on selle supervõime. Jälgite konkreetset elementi ja tagasikutse käivitub ainult siis, kui selle elemendi suurus muutub. See lahutab teie komponendi loogika globaalsest vaateaknast, võimaldades tõelist modulaarsust ja „elemendipäringute” kontseptsiooni.
- Lihtne ja deklaratiivne: API-d on märkimisväärselt lihtne kasutada. Loote vaatleja, ütlete talle, milliseid elemente jälgida, ja pakute ühe tagasikutsefunktsiooni kõigi teadete käsitlemiseks.
- Täpne ja kõikehõlmav: Vaatleja pakub üksikasjalikku teavet uue suuruse kohta, sealhulgas sisukasti, piirjoone kasti ja polsterduse kohta, andes teile täpse kontrolli oma paigutusloogika üle.
Kuidas kasutada ResizeObserverit: praktiline juhend
API kasutamine hõlmab kolme lihtsat sammu: vaatleja loomine, ühe või mitme sihtelemendi jälgimine ja tagasikutseloogika määratlemine. Vaatame seda lähemalt.
Põhisüntaks
API tuumaks on `ResizeObserver` konstruktor ja selle instantsimeetodid.
// 1. Vali element, mida soovid jälgida
const myElement = document.querySelector('.my-component');
// 2. Määratle tagasikutsefunktsioon, mis käivitub suuruse muutuse tuvastamisel
const observerCallback = (entries) => {
for (let entry of entries) {
// 'entry' objekt sisaldab teavet jälgitava elemendi uue suuruse kohta
console.log('Elemendi suurus on muutunud!');
console.log('Sihtelement:', entry.target);
console.log('Uus sisuala ristkülik:', entry.contentRect);
console.log('Uus piirjoone kasti suurus:', entry.borderBoxSize[0]);
}
};
// 3. Loo uus ResizeObserver instants, edastades sellele tagasikutsefunktsiooni
const observer = new ResizeObserver(observerCallback);
// 4. Alusta sihtelemendi jälgimist
observer.observe(myElement);
// Konkreetse elemendi jälgimise lõpetamiseks hiljem:
// observer.unobserve(myElement);
// Kõigi selle vaatlejaga seotud elementide jälgimise lõpetamiseks:
// observer.disconnect();
Tagasikutsefunktsiooni ja selle kirjete mõistmine
Teie pakutav tagasikutsefunktsioon on teie loogika süda. See saab massiivi `ResizeObserverEntry` objektidest. See on massiiv, sest vaatleja saab edastada teateid mitme jälgitava elemendi kohta ühes partiis.
Iga `entry` objekt sisaldab väärtuslikku teavet:
entry.target
: Viide DOM-elemendile, mille suurus muutus.entry.contentRect
: `DOMRectReadOnly` objekt, mis annab elemendi sisukasti mõõtmed (laius, kõrgus, x, y, ülemine, parem, alumine, vasak). See on vanem omadus ja üldiselt soovitatakse kasutada allpool toodud uuemaid kasti suuruse omadusi.entry.borderBoxSize
: Massiiv, mis sisaldab objekti `inlineSize` (laius) ja `blockSize` (kõrgus) elemendi piirjoone kasti jaoks. See on kõige usaldusväärsem ja tulevikukindlam viis elemendi kogusuuruse saamiseks. See on massiiv, et toetada tulevasi kasutusjuhte, nagu mitmeveerulised paigutused, kus element võib olla jaotatud mitmeks fragmendiks. Praegu võite peaaegu alati turvaliselt kasutada esimest elementi: `entry.borderBoxSize[0]`.entry.contentBoxSize
: Sarnane `borderBoxSize`-ga, kuid annab sisukasti (polsterduse sees) mõõtmed.entry.devicePixelContentBoxSize
: Annab sisukasti suuruse seadme pikslites.
Põhiline hea tava: Eelistage `borderBoxSize` ja `contentBoxSize` `contentRect`-le. Need on robustsemad, ühilduvad kaasaegsete CSS-i loogiliste omadustega (`inlineSize` laiuse jaoks, `blockSize` kõrguse jaoks) ja on API jaoks edasine tee.
Reaalse maailma kasutusjuhud ja näited
Teooria on tore, kuid ResizeObserver särab tõeliselt siis, kui näete seda tegevuses. Uurime mõningaid levinud stsenaariume, kus see pakub puhast ja võimsat lahendust.
1. Dünaamilised komponendipaigutused ("Kaardi" näide)
Lahendame `UserInfo` kaardi probleemi, millest varem rääkisime. Tahame, et kaart lülituks horisontaalsest vertikaalsele paigutusele, kui see muutub liiga kitsaks.
HTML:
<div class="card-container">
<div class="user-card">
<img src="avatar.jpg" alt="User Avatar" class="user-card-avatar">
<div class="user-card-info">
<h3>Jane Doe</h3>
<p>Senior Frontend Developer</p>
</div>
</div>
</div>
CSS:
.user-card {
display: flex;
align-items: center;
padding: 1rem;
border: 1px solid #ccc;
border-radius: 8px;
transition: all 0.3s ease;
}
/* Vertikaalse paigutuse olek */
.user-card.is-narrow {
flex-direction: column;
text-align: center;
}
.user-card-avatar {
width: 80px;
height: 80px;
border-radius: 50%;
margin-right: 1rem;
}
.user-card.is-narrow .user-card-avatar {
margin-right: 0;
margin-bottom: 1rem;
}
JavaScript koos ResizeObserveriga:
const card = document.querySelector('.user-card');
const cardObserver = new ResizeObserver(entries => {
for (let entry of entries) {
const { inlineSize } = entry.borderBoxSize[0];
// Kui kaardi laius on alla 350px, lisa 'is-narrow' klass
if (inlineSize < 350) {
entry.target.classList.add('is-narrow');
} else {
entry.target.classList.remove('is-narrow');
}
}
});
cardObserver.observe(card);
Nüüd ei ole oluline, kuhu see kaart paigutatakse. Kui panete selle laia konteinerisse, on see horisontaalne. Kui lohistate konteineri väiksemaks, tuvastab `ResizeObserver` muutuse ja rakendab automaatselt `.is-narrow` klassi, paigutades sisu ümber. See on tõeline komponendi kapseldamine.
2. Reageerivad andmevisualiseeringud ja diagrammid
Andmete visualiseerimise teegid nagu D3.js, Chart.js või ECharts peavad sageli end uuesti joonistama, kui nende konteinerelemendi suurus muutub. See on täiuslik kasutusjuht `ResizeObserver` jaoks.
const chartContainer = document.getElementById('chart-container');
// Eeldame, et 'myChart' on diagrammi instants teegist,
// millel on 'redraw(width, height)' meetod.
const myChart = createMyChart(chartContainer);
const chartObserver = new ResizeObserver(entries => {
const entry = entries[0];
const { inlineSize, blockSize } = entry.contentBoxSize[0];
// Debouncing on siin sageli hea mõte, et vältida liiga sagedast uuesti joonistamist,
// kuigi ResizeObserver juba koondab kutseid.
requestAnimationFrame(() => {
myChart.redraw(inlineSize, blockSize);
});
});
chartObserver.observe(chartContainer);
See kood tagab, et olenemata sellest, kuidas `chart-container` suurust muudetakse – armatuurlaua poolituspaneeli, kokkupandava külgriba või akna suuruse muutmise kaudu – renderdatakse diagramm alati uuesti, et see sobiks ideaalselt oma piiridesse, ilma jõudlust tapvate `window.onresize` kuulajateta.
3. Adaptiivne tüpograafia
Mõnikord soovite, et pealkiri täidaks teatud hulga horisontaalset ruumi, kusjuures selle fondi suurus kohanduks konteineri laiusega. Kuigi CSS-il on nüüd selleks `clamp()` ja konteineripäringu ühikud, annab `ResizeObserver` teile peeneteralise JavaScripti kontrolli.
const adaptiveHeading = document.querySelector('.adaptive-heading');
const headingObserver = new ResizeObserver(entries => {
const entry = entries[0];
const containerWidth = entry.borderBoxSize[0].inlineSize;
// Lihtne valem fondi suuruse arvutamiseks.
// Saate selle teha nii keeruliseks, kui vaja.
const newFontSize = Math.max(16, containerWidth / 10);
entry.target.style.fontSize = `${newFontSize}px`;
});
headingObserver.observe(adaptiveHeading);
4. Kärpimise ja "Loe edasi" linkide haldamine
Levinud kasutajaliidese muster on näidata tekstilõiku ja nuppu "Loe edasi" ainult siis, kui kogu tekst ületab oma konteineri. See sõltub nii konteineri suurusest kui ka sisu pikkusest.
const textBox = document.querySelector('.truncatable-text');
const textContent = textBox.querySelector('p');
const truncationObserver = new ResizeObserver(entries => {
const entry = entries[0];
const target = entry.target;
// Kontrolli, kas kerimiskõrgus on suurem kui kliendi kõrgus
const isOverflowing = target.scrollHeight > target.clientHeight;
target.classList.toggle('is-overflowing', isOverflowing);
});
truncationObserver.observe(textContent);
Teie CSS saab seejärel kasutada `.is-overflowing` klassi, et näidata gradienthajutust ja "Loe edasi" nuppu. Vaatleja tagab, et see loogika käivitub automaatselt, kui konteineri suurus muutub, näidates või peites nuppu õigesti.
Jõudluskaalutlused ja parimad tavad
Kuigi `ResizeObserver` on disaini poolest väga jõudluskeskne, on mõned parimad tavad ja potentsiaalsed lõksud, millest tuleb teadlik olla.
Lõputute tsüklite vältimine
Kõige tavalisem viga on muuta jälgitava elemendi omadust tagasikutse sees, mis omakorda põhjustab uue suuruse muutmise. Näiteks kui lisate elemendile polsterdust, muutub selle suurus, mis käivitab uuesti tagasikutse, mis lisab veel polsterdust ja nii edasi.
// OHT: Lõputu tsükkel!
const badObserver = new ResizeObserver(entries => {
const el = entries[0].target;
// Polsterduse muutmine muudab elemendi suurust, mis käivitab vaatleja uuesti.
el.style.paddingLeft = parseInt(el.style.paddingLeft || 0) + 1 + 'px';
});
Brauserid on targad ja tuvastavad selle. Pärast mõnda kiiret tagasikutset samas kaadris peatuvad nad ja viskavad vea: `ResizeObserver loop limit exceeded`.
Kuidas seda vältida:
- Kontrolli enne muutmist: Enne muudatuse tegemist kontrollige, kas see on tegelikult vajalik. Näiteks meie kaardi näites lisame/eemaldame ainult klassi, me ei muuda pidevalt laiuse omadust.
- Muuda last: Võimalusel pange vaatleja vanemmähisele ja tehke suuruse muudatusi lapselemendile. See katkestab tsükli, kuna jälgitavat elementi ennast ei muudeta.
- Kasuta `requestAnimationFrame`:** Mõnel keerulisel juhul võib DOM-i muudatuse mähkimine `requestAnimationFrame`-i lükata muudatuse järgmisse kaadrisse, katkestades tsükli.
Millal kasutada `unobserve()` ja `disconnect()`
Nagu `addEventListener` puhul, on oluline oma vaatlejad ära koristada, et vältida mälulekkeid, eriti üheleheküljelistes rakendustes (SPA), mis on ehitatud raamistikega nagu React, Vue või Angular.
Kui komponent eemaldatakse või hävitatakse, peaksite kutsuma `observer.unobserve(element)` või `observer.disconnect()`, kui vaatlejat pole enam üldse vaja. Reactis tehakse seda tavaliselt `useEffect` hooki puhastusfunktsioonis. Angularis kasutaksite `ngOnDestroy` elutsükli konksu.
Brauseri tugi
Tänase seisuga toetavad `ResizeObserver`it kõik suuremad kaasaegsed brauserid, sealhulgas Chrome, Firefox, Safari ja Edge. Tugi on globaalsele publikule suurepärane. Projektide jaoks, mis nõuavad tuge väga vanadele brauseritele nagu Internet Explorer 11, saab kasutada polüfilli, kuid enamiku uute projektide jaoks saate API-d julgelt natiivselt kasutada.
ResizeObserver vs. tulevik: CSS-i konteineripäringud
On võimatu arutada `ResizeObserver`it mainimata selle deklaratiivset vastet: CSS-i konteineripäringud. Konteineripäringud (`@container`) võimaldavad teil kirjutada CSS-reegleid, mis kehtivad elemendile selle vanemkonteineri suuruse, mitte vaateakna põhjal.
Meie kaardi näite puhul võiks CSS konteineripäringutega välja näha selline:
.card-container {
container-type: inline-size;
}
/* Kaart ise ei ole konteiner, selle vanem on */
.user-card {
display: flex;
/* ... muud stiilid ... */
}
@container (max-width: 349px) {
.user-card {
flex-direction: column;
}
}
See saavutab sama visuaalse tulemuse kui meie `ResizeObserver` näide, kuid täielikult CSS-is. Kas see muudab `ResizeObserver`i vananenuks? Absoluutselt mitte.
Mõelge neist kui täiendavatest tööriistadest erinevateks töödeks:
- Kasutage CSS-i konteineripäringuid, kui peate muutma elemendi stiili selle konteineri suuruse põhjal. See peaks olema teie vaikimisi valik puhtalt esitluslike muudatuste jaoks.
- Kasutage ResizeObserverit, kui peate käivitama JavaScripti loogikat vastuseks suuruse muutusele. See on hädavajalik ülesannete jaoks, millega CSS hakkama ei saa, näiteks:
- Diagrammiteegi käivitamine uuesti renderdamiseks.
- Keeruliste DOM-manipulatsioonide teostamine.
- Elemendi positsioonide arvutamine kohandatud paigutusmootori jaoks.
- Suhtlemine teiste API-dega elemendi suuruse põhjal.
Nad lahendavad sama põhiprobleemi erinevatest vaatenurkadest. `ResizeObserver` on imperatiivne, programmiline API, samas kui konteineripäringud on deklaratiivne, CSS-natiivne lahendus.
Kokkuvõte: võtke omaks elemenditeadlik disain
ResizeObserver
API on kaasaegse, komponendipõhise veebi fundamentaalne ehituskivi. See vabastab meid vaateakna piirangutest ja annab meile võimaluse ehitada tõeliselt modulaarseid, iseteadlikke komponente, mis suudavad kohaneda igas keskkonnas, kuhu nad paigutatakse. Pakkudes jõudluskeskset ja usaldusväärset viisi elemendi mõõtmete jälgimiseks, kaotab see vajaduse habraste ja ebatõhusate JavaScripti häkkide järele, mis on aastaid vaevanud esiotsa arendust.
Ükskõik, kas ehitate keerulist andmete armatuurlauda, paindlikku disainisüsteemi või lihtsalt ühte korduvkasutatavat vidinat, annab `ResizeObserver` teile täpse kontrolli, mida vajate dünaamiliste paigutuste enesekindlaks ja tõhusaks haldamiseks. See on võimas tööriist, mis koos kaasaegsete paigutustehnikate ja tulevaste CSS-i konteineripäringutega võimaldab vastupidavamat, hooldatavamat ja keerukamat lähenemist reageerivale disainile. On aeg lõpetada mõtlemine ainult lehest ja hakata ehitama komponente, mis mõistavad omaenda ruumi.