Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa React PlatoBlockchain Data Intelligencen kanssa. Pystysuuntainen haku. Ai.

Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa Reactin kanssa

Ne meistä, jotka ovat olleet web-kehittäjiä yli muutaman vuoden, ovat luultavasti kirjoittaneet koodia useammalla kuin yhdellä JavaScript-kehyksellä. Kaikilla vaihtoehdoilla – React, Svelte, Vue, Angular, Solid – se on kaikkea muuta kuin väistämätöntä. Yksi turhauttavimmista asioista, joita joudumme käsittelemään työskennellessämme eri kehysten välillä, on luoda uudelleen kaikki matalan tason käyttöliittymäkomponentit: painikkeet, välilehdet, pudotusvalikot jne. Erityisen turhauttavaa on, että ne on yleensä määritelty yhdessä kehyksessä. , sano React, mutta täytyy sitten kirjoittaa ne uudelleen, jos haluamme rakentaa jotain Svelteen. Tai Vue. Tai Kiinteä. Ja niin edelleen.

Eikö olisi parempi, jos voisimme määritellä nämä matalan tason käyttöliittymäkomponentit kerran kehysagnostisella tavalla ja sitten käyttää niitä uudelleen kehysten välillä? Tietysti olisi! Ja me voimme; verkkokomponentit ovat oikea tapa. Tämä viesti näyttää sinulle kuinka.

Toistaiseksi verkkokomponenttien SSR-tarina on hieman puutteellinen. Deklarative shadow DOM (DSD) on tapa, jolla verkkokomponentti hahmonnetaan palvelinpuolella, mutta tätä kirjoitettaessa sitä ei ole integroitu suosikkisovelluskehyksiisi, kuten Next, Remix tai SvelteKit. Jos tämä on sinulle vaatimus, muista tarkistaa DSD:n uusin tila. Mutta muuten, jos SSR ei ole jotain, jota käytät, lue eteenpäin.

Ensinnäkin jokin asiayhteys

Verkkokomponentit ovat pohjimmiltaan HTML-elementtejä, jotka määrittelet itse, kuten <yummy-pizza> tai mitä tahansa, alusta alkaen. Niitä käsitellään kaikkialla täällä CSS-Tricksissä (mukaan lukien Caleb Williamsin laaja sarja ja yksi John Rhealta), mutta käymme lyhyesti läpi prosessin. Pohjimmiltaan määrittelet JavaScript-luokan, perit sen HTMLElementja määritä sitten verkkokomponentin ominaisuudet, attribuutit ja tyylit sekä tietysti merkinnät, jonka se lopulta hahmontaa käyttäjillesi.

Mahdollisuus määrittää mukautettuja HTML-elementtejä, jotka eivät ole sidottu mihinkään tiettyyn komponenttiin, on jännittävää. Mutta tämä vapaus on myös rajoitus. JavaScript-kehyksestä riippumaton olemassaolo tarkoittaa, että et voi olla vuorovaikutuksessa näiden JavaScript-kehysten kanssa. Ajattele React-komponenttia, joka hakee osan datasta ja hahmontaa sitten osan muut Reagoi komponentti, joka välittää tietoja. Tämä ei todellakaan toimisi verkkokomponenttina, koska verkkokomponentti ei osaa hahmontaa React-komponenttia.

Verkkokomponentit ovat erityisen hyviä lehtien komponentit. Lehtien komponentit ovat viimeinen asia, joka renderöidään komponenttipuussa. Nämä ovat komponentteja, jotka saavat joitain rekvisiitta ja renderöivät joitain UI. Nämä ovat emme komponentit, jotka istuvat komponenttipuun keskellä, välittävät tietoja, asettavat kontekstin jne. – vain osia UI joka näyttää samalta riippumatta siitä, mikä JavaScript-kehys käyttää muuta sovellusta.

Verkkokomponentti, jota olemme rakentamassa

Sen sijaan, että rakennamme jotain tylsää (ja yleistä), kuten nappia, rakentakaamme jotain hieman erilaista. minun lastaus viesti Tarkastelimme epäselvien kuvien esikatselun käyttöä estääksemme sisällön uudelleenjuoksun ja tarjotaksemme käyttäjille kunnollisen käyttöliittymän kuviemme latautuessa. Tarkastelimme base64:ää, joka koodaa kuviemme epäselviä, huonontuneita versioita ja osoitti sen käyttöliittymässämme todellisen kuvan latauksen aikana. Tarkastelimme myös luoda uskomattoman kompakteja, epäselviä esikatseluita käyttämällä työkalua nimeltä Blurhash.

Tämä viesti osoitti, kuinka voit luoda esikatselut ja käyttää niitä React-projektissa. Tämä viesti näyttää sinulle, kuinka voit käyttää näitä esikatseluita verkkokomponentista, jotta ne voivat käyttää niitä Kaikki JavaScript-kehys.

Mutta meidän on käveltävä ennen kuin voimme juosta, joten käymme ensin läpi jotain triviaalia ja typerää nähdäksemme tarkalleen kuinka verkkokomponentit toimivat.

Kaikki tässä viestissä rakentaa vaniljaverkkokomponentteja ilman työkaluja. Tämä tarkoittaa, että koodissa on hieman kapeaa, mutta sen pitäisi olla suhteellisen helppo seurata. Työkalut kuten Lit or Sapluuna on suunniteltu rainakomponenttien rakentamiseen, ja niitä voidaan käyttää poistamaan suuri osa tästä kattilalevystä. Kehotan sinua tarkistamaan ne! Mutta tässä postauksessa haluan mieluummin hieman enemmän kattilaa vastineeksi siitä, ettei tarvitse esitellä ja opettaa toista riippuvuutta.

Yksinkertainen laskurikomponentti

Rakennetaan klassinen "Hello World" JavaScript-komponenteista: laskuri. Luomme arvon ja painikkeen, joka lisää arvoa. Yksinkertainen ja tylsä, mutta sen avulla voimme tarkastella yksinkertaisinta mahdollista verkkokomponenttia.

Verkkokomponentin rakentamiseksi ensimmäinen askel on tehdä JavaScript-luokka, joka perii osoitteesta HTMLElement:

class Counter extends HTMLElement {}

Viimeinen vaihe on verkkokomponentin rekisteröinti, mutta vain, jos emme ole vielä rekisteröineet sitä:

if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter);
}

Ja tietysti renderöi se:

<counter-wc></counter-wc>

Ja kaikki siltä väliltä on se, että saamme verkkokomponentin tekemään mitä haluamme. Yksi yleinen elinkaarimenetelmä on connectedCallback, joka käynnistyy, kun verkkokomponenttimme lisätään DOM:iin. Voisimme käyttää tätä menetelmää minkä tahansa sisällön hahmontamiseen. Muista, että tämä on JS-luokka, joka periytyy HTMLElement, mikä tarkoittaa meidän this arvo on itse verkkokomponenttielementti, jossa on kaikki normaalit DOM-käsittelymenetelmät, jotka jo tunnet ja rakastat.

Yksinkertaisimmin voisimme tehdä tämän:

class Counter extends HTMLElement { connectedCallback() { this.innerHTML = "<div style='color: green'>Hey</div>"; }
} if (!customElements.get("counter-wc")) { customElements.define("counter-wc", Counter);
}

…joka toimii hyvin.

Sana "hei" vihreällä.
Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa Reactin kanssa

Todellisen sisällön lisääminen

Lisätään hyödyllistä, interaktiivista sisältöä. Me tarvitsemme <span> nykyisen numeroarvon säilyttämiseksi ja a <button> nostaaksesi laskuria. Toistaiseksi luomme tämän sisällön rakentajassamme ja lisäämme sen, kun verkkokomponentti on todella DOM:ssa:

constructor() { super(); const container = document.createElement('div'); this.valSpan = document.createElement('span'); const increment = document.createElement('button'); increment.innerText = 'Increment'; increment.addEventListener('click', () => { this.#value = this.#currentValue + 1; }); container.appendChild(this.valSpan); container.appendChild(document.createElement('br')); container.appendChild(increment); this.container = container;
} connectedCallback() { this.appendChild(this.container); this.update();
}

Jos olet todella tyrmistynyt manuaalisesta DOM-luonnosta, muista, että voit määrittää innerHTML, tai jopa luo mallielementti kerran verkkokomponenttiluokkasi staattisena ominaisuutena, kloonaa se ja lisää uusien verkkokomponenttien sisältö. On luultavasti joitain muita vaihtoehtoja, joita en ajattele, tai voit aina käyttää verkkokomponenttikehystä, kuten Lit or Sapluuna. Mutta tässä viestissä pidämme asian yksinkertaisena.

Jatkettaessa tarvitsemme asetettavan JavaScript-luokan ominaisuuden nimeltä value

#currentValue = 0; set #value(val) { this.#currentValue = val; this.update();
}

Se on vain vakioluokan ominaisuus, jossa on asettaja, sekä toinen ominaisuus arvon säilyttämiseksi. Yksi hauska käänne on, että käytän yksityistä JavaScript-luokan ominaisuuden syntaksia näille arvoille. Tämä tarkoittaa, että kukaan verkkokomponenttimme ulkopuolella ei voi koskaan koskea näihin arvoihin. Tämä on vakio JavaScript jota tuetaan kaikissa nykyaikaisissa selaimissa, joten älä pelkää käyttää sitä.

Tai soita rohkeasti _value jos sinä suosit. Ja lopuksi meidän update menetelmä:

update() { this.valSpan.innerText = this.#currentValue;
}

Se toimii!

Vastaverkon komponentti.
Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa Reactin kanssa

Ilmeisesti tämä ei ole koodi, jota haluat ylläpitää mittakaavassa. Tässä on täysi toimiva esimerkki jos haluat katsoa tarkemmin. Kuten sanoin, työkalut, kuten Lit ja Stencil, on suunniteltu tekemään tästä yksinkertaisempi.

Lisää toimintoja

Tämä viesti ei ole syvällinen sukellus verkkokomponentteihin. Emme kata kaikkia sovellusliittymiä ja elinkaaria; emme edes peitä varjojuuret tai raot. Näistä aiheista on loputtomasti sisältöä. Tavoitteeni on tarjota tarpeeksi kunnollinen johdatus herättämään kiinnostusta sekä hyödyllisiä ohjeita itse asiassa käyttämällä verkkokomponentit suosituilla JavaScript-kehyksillä, jotka jo tunnet ja joista pidät.

Sitä varten parannetaan hieman laskuriverkkokomponenttiamme. Hyväksytään se a color attribuutti, jolla voit hallita näytettävän arvon väriä. Ja hyväksytään se myös an increment ominaisuuden, joten tämän verkkokomponentin kuluttajat voivat kasvattaa sitä 2, 3, 4 kerrallaan. Ja näiden tilamuutosten ajamiseksi käytetään uutta laskuriamme Svelte-hiekkalaatikossa – pääsemme Reactiin hetken kuluttua.

Aloitamme samalla verkkokomponentilla kuin aiemmin ja lisäämme värimääritteen. Määrittelemme verkkokomponenttimme hyväksymään määritteen ja vastaamaan siihen lisäämällä staattisen observedAttributes ominaisuus, joka palauttaa attribuutit, joita verkkokomponenttimme kuuntelee.

static observedAttributes = ["color"];

Kun tämä on paikallaan, voimme lisätä a attributeChangedCallback elinkaarimenetelmä, joka suoritetaan aina, kun jokin kohdassa luetelluista määritteistä täyttyy observedAttributes on asetettu tai päivitetty.

attributeChangedCallback(name, oldValue, newValue) { if (name === "color") { this.update(); }
}

Nyt päivitämme omaa update tapa todella käyttää sitä:

update() { this.valSpan.innerText = this._currentValue; this.valSpan.style.color = this.getAttribute("color") || "black";
}

Lisätään lopuksi omamme increment omaisuus:

increment = 1;

Yksinkertaista ja nöyriä.

Svelten laskurikomponentin käyttö

Käytetään sitä mitä juuri teimme. Siirrymme Svelte-sovelluskomponenttiin ja lisäämme jotain tämän kaltaista:

<script> let color = "red";
</script> <style> main { text-align: center; }
</style> <main> <select bind:value={color}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc color={color}></counter-wc>
</main>

Ja se toimii! Laskurimme renderöi, lisää ja pudotusvalikko päivittää värin. Kuten näet, renderöimme väriattribuutin Svelte-mallissamme ja kun arvo muuttuu, Svelte hoitaa kutsumisen. setAttribute taustalla olevassa verkkokomponenttiesiintymässämme. Tässä ei ole mitään erikoista: tämä on sama asia, jota se jo tekee attribuuteille Kaikki HTML-elementti.

Asiat ovat hieman mielenkiintoisia increment prop. Tämä on emme attribuutti verkkokomponentissamme; se on web-komponentin luokka. Tämä tarkoittaa, että se on asetettava verkkokomponentin ilmentymään. Kannata minua, sillä asiat päätyvät paljon yksinkertaisempaan hetkessä.

Ensin lisäämme joitain muuttujia Svelte-komponenttiin:

let increment = 1;
let wcInstance;

Laskurikomponenttimme voimavaramme antaa sinun kasvattaa yhdellä tai kahdella:

<button on:click={() => increment = 1}>Increment 1</button>
<button on:click={() => increment = 2}>Increment 2</button>

Mutta, teoriassa, meidän on saatava verkkokomponenttimme todellinen esiintymä. Tämä on sama asia, jonka teemme aina, kun lisäämme a ref Reactin kanssa. Svelten kanssa se on yksinkertaista bind:this direktiivi:

<counter-wc bind:this={wcInstance} color={color}></counter-wc>

Nyt Svelte-mallissamme kuuntelemme komponenttimme lisäysmuuttujan muutoksia ja asetamme taustalla olevan verkkokomponentin ominaisuuden.

$: { if (wcInstance) { wcInstance.increment = increment; }
}

Voit testata sitä tässä live-demossa.

Emme tietenkään halua tehdä tätä jokaiselle verkkokomponentille tai -sisällölle, jota meidän on hallittava. Eikö olisi mukavaa, jos voisimme vain asettaa increment suoraan verkkokomponentissamme merkinnöissä, kuten yleensä teemme komponenttien rekvisiittalle, ja saat sen, tiedäthän, vain työtä? Toisin sanoen olisi mukavaa, jos voisimme poistaa kaikki käytöt wcInstance ja käytä sen sijaan tätä yksinkertaisempaa koodia:

<counter-wc increment={increment} color={color}></counter-wc>

Osoittautuu, että voimme. Tämä koodi toimii; Svelte hoitaa kaiken tämän jalkatyön puolestamme. Katso se tästä demosta. Tämä on normaalia toimintaa melkein kaikille JavaScript-kehyksille.

Joten miksi näytin sinulle manuaalisen tavan asettaa verkkokomponentin tuki? Kaksi syytä: on hyödyllistä ymmärtää, miten nämä asiat toimivat, ja hetki sitten sanoin, että tämä toimii "melko paljon" kaikissa JavaScript-kehyksissä. Mutta on yksi kehys, joka ällöttävästi ei tue verkkokomponenttien asetuksia, kuten juuri näimme.

React on erilainen peto

Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa React PlatoBlockchain Data Intelligencen kanssa. Pystysuuntainen haku. Ai.
Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa Reactin kanssa

Reagoi. Planeetan suosituin JavaScript-kehys ei tue perusyhteensopivuutta verkkokomponenttien kanssa. Tämä on hyvin tunnettu ongelma, joka on ainutlaatuinen Reactille. Mielenkiintoista on, että tämä on itse asiassa korjattu Reactin kokeellisessa haarassa, mutta jostain syystä sitä ei ole yhdistetty versioon 18. Voimme kuitenkin edelleen seurata sen edistymistä. Ja voit kokeilla tätä itse a live demo.

Ratkaisu on tietysti käyttää a ref, ota verkkokomponentin ilmentymä ja aseta se manuaalisesti increment kun se arvo muuttuu. Se näyttää tältä:

import React, { useState, useRef, useEffect } from 'react';
import './counter-wc'; export default function App() { const [increment, setIncrement] = useState(1); const [color, setColor] = useState('red'); const wcRef = useRef(null); useEffect(() => { wcRef.current.increment = increment; }, [increment]); return ( <div> <div className="increment-container"> <button onClick={() => setIncrement(1)}>Increment by 1</button> <button onClick={() => setIncrement(2)}>Increment by 2</button> </div> <select value={color} onChange={(e) => setColor(e.target.value)}> <option value="red">Red</option> <option value="green">Green</option> <option value="blue">Blue</option> </select> <counter-wc ref={wcRef} increment={increment} color={color}></counter-wc> </div> );
}

Kuten keskustelimme, tämän koodaaminen manuaalisesti jokaiselle verkkokomponenttiomaisuudelle ei yksinkertaisesti ole skaalattavissa. Mutta kaikki ei ole menetetty, koska meillä on pari vaihtoehtoa.

Vaihtoehto 1: Käytä attribuutteja kaikkialla

Meillä on ominaisuuksia. Jos napsautit yllä olevaa React-demoa, increment potkuri ei toiminut, mutta väri muuttui oikein. Emmekö voi koodata kaikkea attribuuttien avulla? Valitettavasti ei. Attribuuttien arvot voivat olla vain merkkijonoja. Se riittää täällä, ja tällä lähestymistavalla pääsisimme jokseenkin pitkälle. Numerot kuten increment voidaan muuntaa merkkijonoiksi ja niistä. Voisimme jopa JSON stringify / jäsentää objekteja. Mutta lopulta meidän on siirrettävä funktio verkkokomponenttiin, ja siinä vaiheessa vaihtoehtoja ei enää ole.

Vaihtoehto 2: Kääri se

Vanha sanonta sanoo, että voit ratkaista minkä tahansa tietojenkäsittelytieteen ongelman lisäämällä epäsuoran tason (paitsi liian monen epäsuoran tason ongelma). Koodi näiden rekvisiittajen asettamiseen on melko ennustettavissa ja yksinkertainen. Entä jos piilotamme sen kirjastoon? Älykkäät ihmiset Litin takana on yksi ratkaisu. Tämä kirjasto luo sinulle uuden React-komponentin, kun annat sille verkkokomponentin ja luettelee sen tarvitsemat ominaisuudet. Vaikka olen älykäs, en ole tämän lähestymistavan fani.

Sen sijaan, että verkkokomponentit yhdistettäisiin yksitellen manuaalisesti luotuihin React-komponentteihin, haluan vain yksi Reagoi komponentti, että välitämme verkkokomponenttimme merkin nimi kohteeseen (counter-wc meidän tapauksessamme) – sekä kaikki attribuutit ja ominaisuudet – ja jotta tämä komponentti renderöi verkkokomponenttimme, lisää ref, selvitä sitten mikä on rekvisiitta ja mikä attribuutti. Se on mielestäni ihanteellinen ratkaisu. En tiedä kirjastoa, joka tekee tämän, mutta sen luomisen pitäisi olla yksinkertaista. Kokeillaan!

Tämä on käyttö etsimme:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

wcTag on verkkokomponentin tunnisteen nimi; loput ovat ominaisuuksia ja attribuutteja, jotka haluamme välittää eteenpäin.

Toteutukseni näyttää tältä:

import React, { createElement, useRef, useLayoutEffect, memo } from 'react'; const _WcWrapper = (props) => { const { wcTag, children, ...restProps } = props; const wcRef = useRef(null); useLayoutEffect(() => { const wc = wcRef.current; for (const [key, value] of Object.entries(restProps)) { if (key in wc) { if (wc[key] !== value) { wc[key] = value; } } else { if (wc.getAttribute(key) !== value) { wc.setAttribute(key, value); } } } }); return createElement(wcTag, { ref: wcRef });
}; export const WcWrapper = memo(_WcWrapper);

Mielenkiintoisin rivi on lopussa:

return createElement(wcTag, { ref: wcRef });

Näin luomme Reactissa elementin dynaamisella nimellä. Itse asiassa tämä on se, mitä React tavallisesti muuntaa JSX:n. Kaikki divimme on muunnettu muotoiksi createElement("div") puhelut. Meidän ei normaalisti tarvitse kutsua tätä API:ta suoraan, mutta se on siellä, kun tarvitsemme sitä.

Tämän lisäksi haluamme suorittaa asetteluvaikutelman ja silmukan läpi jokaisen komponentillemme siirtämämme rekvisiitin. Käymme ne kaikki läpi ja tarkistamme, onko kyseessä kiinteistö, jossa on in Tarkista, että se tarkistaa verkkokomponentin ilmentymän objektin sekä sen prototyyppiketjun, joka saa kiinni kaikki luokan prototyyppiin päätyvät getterit/setterit. Jos tällaista ominaisuutta ei ole, sen oletetaan olevan attribuutti. Kummassakin tapauksessa asetamme sen vain, jos arvo on todella muuttunut.

Jos mietit miksi käytämme useLayoutEffect sijasta useEffect, koska haluamme suorittaa nämä päivitykset välittömästi ennen kuin sisältömme hahmonnetaan. Huomaa myös, että meillä ei ole riippuvuusjoukkoa useLayoutEffect; tämä tarkoittaa, että haluamme suorittaa tämän päivityksen jokainen renderöinti. Tämä voi olla riskialtista, koska Reactilla on taipumus renderöidä uudelleen paljon. Parannan tätä käärimällä koko asian React.memo. Tämä on pohjimmiltaan nykyaikainen versio React.PureComponent, mikä tarkoittaa, että komponentti hahmonnetaan uudelleen vain, jos jokin sen varsinaisista rekvisiittauksista on muuttunut – ja se tarkistaa, onko näin tapahtunut yksinkertaisella tasa-arvotarkistuksella.

Ainoa riski tässä on, että jos ohitat mutaatiossa olevan objektin ehdotuksen suoraan ilman uudelleenmäärittämistä, et näe päivityksiä. Mutta tämä on erittäin masentavaa, varsinkin React-yhteisössä, joten en olisi siitä huolissani.

Ennen kuin jatkan, haluaisin sanoa vielä yhden asian. Et ehkä ole tyytyväinen siihen, miltä käyttö näyttää. Jälleen tätä komponenttia käytetään seuraavasti:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

Erityisesti et ehkä pidä verkkokomponentin tunnisteen nimen välittämisestä <WcWrapper> komponentti ja mieluummin sen sijaan @lit-labs/react yllä oleva paketti, joka luo uuden yksittäisen React-komponentin jokaiselle verkkokomponentille. Se on täysin reilua, ja kehotan sinua käyttämään sitä, mikä sinulle parhaiten sopii. Mutta minulle tämän lähestymistavan yksi etu on, että se on helppo tehdä poistaa. Jos React yhdistää jonkin ihmeen kautta oikean verkkokomponenttien käsittelyn kokeellisesta haarastaan main huomenna voit muuttaa yllä olevan koodin tästä:

<WcWrapper wcTag="counter-wc" increment={increment} color={color} />

…tähän:

<counter-wc ref={wcRef} increment={increment} color={color} />

Voisit luultavasti jopa kirjoittaa yhden codemodin tehdäksesi sen kaikkialla ja sitten poistaa <WcWrapper> yhteensä. Itse asiassa, raaputa se: yleinen haku ja korvaaminen säännöllisellä lausekkeella toimisi todennäköisesti.

Toimeenpano

Tiedän, näyttää siltä, ​​että tänne pääsy kesti matkan. Jos muistat, alkuperäinen tavoitteemme oli ottaa kuvan esikatselukoodi, jota katsoimme omassani lastaus viesti, ja siirrä se verkkokomponenttiin, jotta sitä voidaan käyttää missä tahansa JavaScript-kehyksessä. Reactin kunnollisen yhteistoiminnan puute lisäsi sekoitukseen paljon yksityiskohtia. Mutta nyt, kun meillä on kunnollinen kahva verkkokomponentin luomiseen ja sen käyttöön, toteutus on melkein anti-klimaktinen.

Pudotan koko verkkokomponentin tähän ja tuon esiin joitain mielenkiintoisia kohtia. Jos haluat nähdä sen toiminnassa, tässä on a toimiva demo. Se vaihtaa kolmen suosikkikirjani välillä kolmella suosikkiohjelmointikielelläni. Kunkin kirjan URL-osoite on joka kerta yksilöllinen, joten voit nähdä esikatselun, mutta haluat todennäköisesti rajoittaa asioita DevTools Network -välilehdellä nähdäksesi asioiden todella tapahtuvan.

Näytä koko koodi
class BookCover extends HTMLElement { static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); } } set preview(val) { this.previewEl = this.createPreview(val); this.render(); } createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); } } createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () =&gt; { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img; } connectedCallback() { this.render(); } render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe); }
}

Ensin rekisteröidään attribuutti, josta olemme kiinnostuneita, ja reagoimme sen muuttuessa:

static observedAttributes = ['url']; attributeChangedCallback(name, oldValue, newValue) { if (name === 'url') { this.createMainImage(newValue); }
}

Tämä saa aikaan kuvakomponenttimme luomisen, joka näkyy vain ladattaessa:

createMainImage(url) { this.loaded = false; const img = document.createElement('img'); img.alt = 'Book cover'; img.addEventListener('load', () => { if (img === this.imageEl) { this.loaded = true; this.render(); } }); img.src = url; this.imageEl = img;
}

Seuraavaksi meillä on esikatseluominaisuus, joka voi olla joko base64-esikatselumerkkijono tai meidän blurhash paketti:

set preview(val) { this.previewEl = this.createPreview(val); this.render();
} createPreview(val) { if (typeof val === 'string') { return base64Preview(val); } else { return blurHashPreview(val); }
}

Tämä siirtää tarvitsemamme aputoiminnon:

function base64Preview(val) { const img = document.createElement('img'); img.src = val; return img;
} function blurHashPreview(preview) { const canvasEl = document.createElement('canvas'); const { w: width, h: height } = preview; canvasEl.width = width; canvasEl.height = height; const pixels = decode(preview.blurhash, width, height); const ctx = canvasEl.getContext('2d'); const imageData = ctx.createImageData(width, height); imageData.data.set(pixels); ctx.putImageData(imageData, 0, 0); return canvasEl;
}

Ja lopuksi meidän render menetelmä:

connectedCallback() { this.render();
} render() { const elementMaybe = this.loaded ? this.imageEl : this.previewEl; syncSingleChild(this, elementMaybe);
}

Ja muutama apumenetelmä kaiken yhdistämiseksi:

export function syncSingleChild(container, child) { const currentChild = container.firstElementChild; if (currentChild !== child) { clearContainer(container); if (child) { container.appendChild(child); } }
} export function clearContainer(el) { let child; while ((child = el.firstElementChild)) { el.removeChild(child); }
}

Se on hieman laajempi kuin mitä tarvitsisimme, jos rakennamme tämän kehykseen, mutta hyvä puoli on, että voimme käyttää tätä uudelleen missä tahansa kehyksessä – vaikka React tarvitsee toistaiseksi kääreen, kuten keskustelimme. .

Sekalaisia ​​asioita

Olen jo maininnut Litin React-kääreen. Mutta jos huomaat käyttäväsi Stenciliä, se todella tukee a erillinen ulostuloputki vain Reactille. Ja Microsoftin hyvät ihmiset ovat myös tehneet loi jotain samanlaista kuin Litin kääre, joka on liitetty Fast Web -komponenttikirjastoon.

Kuten mainitsin, kaikki puitteet, joita ei ole nimetty React, käsittelevät verkkokomponenttien ominaisuuksien asettamisen puolestasi. Huomaa vain, että joillain on joitain erityisiä syntaksin makuja. Esimerkiksi Solid.js:n avulla <your-wc value={12}> olettaa aina niin value on ominaisuus, jonka voit ohittaa a attr etuliite, kuten <your-wc attr:value={12}>.

Käärimistä

Verkkokomponentit ovat mielenkiintoinen, usein liian vähän käytetty osa verkkokehitysmaisemaa. Ne voivat auttaa vähentämään riippuvuuttasi yksittäisestä JavaScript-kehyksestä hallitsemalla käyttöliittymääsi tai "lehtikomponentteja". Vaikka näiden luominen verkkokomponenteiksi – toisin kuin Svelte- tai React-komponentit – ei ole yhtä ergonomista, kääntöpuolena on, että niitä voidaan käyttää laajasti uudelleen.


Rakenna yhteentoimivia verkkokomponentteja, jotka toimivat jopa Reactin kanssa alun perin julkaistu CSS-temppuja. Sinun pitäisi hanki uutiskirje.

Aikaleima:

Lisää aiheesta CSS-temppuja