Interoperabele webcomponenten bouwen die zelfs werken met React PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.

Interoperabele webcomponenten bouwen die zelfs werken met React

Degenen onder ons die al meer dan een paar jaar webontwikkelaars zijn, hebben waarschijnlijk code geschreven met meer dan één JavaScript-framework. Met alle keuzes die er zijn - React, Svelte, Vue, Angular, Solid - is het bijna onvermijdelijk. Een van de meer frustrerende dingen waarmee we te maken hebben bij het werken in verschillende frameworks, is het opnieuw maken van al die UI-componenten op laag niveau: knoppen, tabbladen, vervolgkeuzelijsten, enz. Wat vooral frustrerend is, is dat we ze meestal in één raamwerk hebben gedefinieerd , zeg React, maar dan moeten we ze herschrijven als we iets in Svelte willen bouwen. Of Vue. Of solide. Enzovoort.

Zou het niet beter zijn als we deze low-level UI-componenten eenmalig zouden kunnen definiëren, op een framework-agnostische manier, en ze vervolgens tussen frameworks opnieuw zouden kunnen gebruiken? Natuurlijk zou het! En we kunnen; webcomponenten zijn de weg. Dit bericht laat je zien hoe.

Vanaf nu ontbreekt het SSR-verhaal voor webcomponenten een beetje. Declarative shadow DOM (DSD) is hoe een webcomponent aan de serverzijde wordt weergegeven, maar op dit moment is het niet geïntegreerd met uw favoriete applicatieframeworks zoals Next, Remix of SvelteKit. Als dat een vereiste voor u is, controleer dan de laatste status van DSD. Maar lees verder als SSR niet iets is dat u gebruikt.

Eerst wat context

Webcomponenten zijn in wezen HTML-elementen die u zelf definieert, zoals: <yummy-pizza> of wat dan ook, van de grond af aan. Ze worden hier allemaal behandeld bij CSS-Tricks (inclusief een uitgebreide serie van Caleb Williams en een van John Rhea) maar we zullen het proces kort doornemen. In wezen definieert u een JavaScript-klasse, erft u deze van HTMLElement, en definieer vervolgens welke eigenschappen, attributen en stijlen de webcomponent heeft en, natuurlijk, de opmaak die het uiteindelijk aan uw gebruikers zal weergeven.

Het is opwindend om aangepaste HTML-elementen te kunnen definiëren die niet aan een bepaald onderdeel zijn gebonden. Maar deze vrijheid is ook een beperking. Bestaande onafhankelijk van een JavaScript-framework betekent dat u niet echt kunt communiceren met die JavaScript-frameworks. Denk aan een React-component die wat gegevens ophaalt en vervolgens wat weergeeft anders Reageer component, doorgeven van de gegevens. Dit zou niet echt werken als een webcomponent, omdat een webcomponent niet weet hoe een React-component moet worden weergegeven.

Webcomponenten blinken vooral uit als blad onderdelen. Bladcomponenten zijn het laatste dat wordt weergegeven in een componentenboom. Dit zijn de componenten die sommige rekwisieten ontvangen, en sommige renderen UI. Dit zijn niet de componenten die in het midden van uw componentenboom zitten, gegevens doorgeven, context instellen, enz. - gewoon pure stukjes UI dat zal er hetzelfde uitzien, ongeacht welk JavaScript-framework de rest van de app aandrijft.

De webcomponent die we bouwen

Laten we in plaats van iets saais (en gewoons), zoals een knop, iets anders te bouwen. In mijn laad-bericht we hebben gekeken naar het gebruik van wazige afbeeldingsvoorbeelden om te voorkomen dat inhoud opnieuw wordt geplaatst en om gebruikers een fatsoenlijke gebruikersinterface te bieden terwijl onze afbeeldingen worden geladen. We hebben gekeken naar base64-codering van een wazige, gedegradeerde versie van onze afbeeldingen, en dat laten zien in onze gebruikersinterface terwijl de echte afbeelding werd geladen. We hebben ook gekeken naar het genereren van ongelooflijk compacte, wazige voorvertoningen met behulp van een tool genaamd Blurash.

Dat bericht liet je zien hoe je die previews kunt genereren en gebruiken in een React-project. Dit bericht laat je zien hoe je die voorbeelden van een webcomponent kunt gebruiken, zodat ze kunnen worden gebruikt door elke JavaScript-framework.

Maar we moeten lopen voordat we kunnen rennen, dus we zullen eerst door iets triviaals en dwaas lopen om te zien hoe webcomponenten precies werken.

Alles in dit bericht zal vanilla-webcomponenten bouwen zonder enige tooling. Dat betekent dat de code een beetje standaard is, maar relatief eenvoudig te volgen moet zijn. Tools zoals bed or Stencil zijn ontworpen voor het bouwen van webcomponenten en kunnen worden gebruikt om een ​​groot deel van deze standaardtekst te verwijderen. Ik nodig je uit om ze te bekijken! Maar voor dit bericht geef ik de voorkeur aan een beetje meer standaardtekst in ruil voor het niet hoeven introduceren en onderwijzen van een andere afhankelijkheid.

Een eenvoudige tegencomponent

Laten we de klassieke "Hello World" van JavaScript-componenten bouwen: een teller. We zullen een waarde weergeven en een knop die die waarde verhoogt. Eenvoudig en saai, maar het laat ons kijken naar de eenvoudigst mogelijke webcomponent.

Om een ​​webcomponent te bouwen, is de eerste stap het maken van een JavaScript-klasse, die erft van HTMLElement:

class Counter extends HTMLElement {}

De laatste stap is het registreren van de webcomponent, maar alleen als we deze nog niet hebben geregistreerd:

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

En natuurlijk geef je het weer:

<counter-wc></counter-wc>

En alles daartussenin is dat wij de webcomponent laten doen wat we willen. Een veelgebruikte levenscyclusmethode is: connectedCallback, die wordt geactiveerd wanneer onze webcomponent wordt toegevoegd aan de DOM. We zouden die methode kunnen gebruiken om elke gewenste inhoud weer te geven. Onthoud dat dit een JS-klasse is die is geërfd van HTMLElement, wat betekent onze this value is het webcomponentelement zelf, met alle normale DOM-manipulatiemethoden die u al kent en waar u van houdt.

Op zijn eenvoudigst zouden we dit kunnen doen:

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

... wat prima zal werken.

Het woord "hey" in het groen.
Interoperabele webcomponenten bouwen die zelfs werken met React

Echte inhoud toevoegen

Laten we wat nuttige, interactieve inhoud toevoegen. We hebben een ... nodig <span> om de huidige getalwaarde vast te houden en a <button> om de teller te verhogen. Voorlopig maken we deze inhoud in onze constructor en voegen we deze toe wanneer de webcomponent zich daadwerkelijk in de DOM bevindt:

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();
}

Als je echt geëxtrapoleerd bent door de handmatige DOM-creatie, onthoud dan dat je kunt instellen innerHTML, of maak zelfs eenmaal een sjabloonelement als een statische eigenschap van uw webcomponentklasse, kloon het en voeg de inhoud in voor nieuwe webcomponentinstanties. Er zijn waarschijnlijk een aantal andere opties waar ik niet aan denk, of je kunt altijd een webcomponentframework gebruiken zoals bed or Stencil. Maar voor dit bericht blijven we het simpel houden.

Verderop hebben we een instelbare JavaScript-klasse-eigenschap nodig met de naam value

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

Het is gewoon een standaard klasse-eigenschap met een setter, samen met een tweede eigenschap om de waarde vast te houden. Een leuke twist is dat ik de privé-syntaxis van de JavaScript-klasse-eigenschap voor deze waarden gebruik. Dat betekent dat niemand buiten onze webcomponent ooit aan deze waarden kan raken. Dit is standaard JavaScript dat wordt ondersteund in alle moderne browsers, dus wees niet bang om het te gebruiken.

Of bel gerust _value als je wilt. En als laatste onze update methode:

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

Het werkt!

De teller webcomponent.
Interoperabele webcomponenten bouwen die zelfs werken met React

Het is duidelijk dat dit geen code is die u op grote schaal wilt handhaven. Hier is een volledige werkend voorbeeld als je het van dichterbij wilt bekijken. Zoals ik al zei, zijn tools zoals Lit en Stencil ontworpen om dit eenvoudiger te maken.

Wat meer functionaliteit toevoegen

Dit bericht is geen diepe duik in webcomponenten. We zullen niet alle API's en levenscycli behandelen; we zullen niet eens dekken schaduwwortels of sleuven. Er is eindeloze inhoud over die onderwerpen. Mijn doel hier is om een ​​behoorlijke introductie te geven om enige interesse te wekken, samen met wat nuttige begeleiding over eigenlijk gebruik webcomponenten met de populaire JavaScript-frameworks die u al kent en waar u van houdt.

Laten we daarom onze counter-webcomponent een beetje verbeteren. Laten we het accepteren a color attribuut, om de kleur te bepalen van de waarde die wordt weergegeven. En laten we het ook accepteren een increment eigenschap, zodat gebruikers van deze webcomponent deze met 2, 3, 4 per keer kunnen verhogen. En om deze toestandsveranderingen aan te sturen, laten we onze nieuwe teller gebruiken in een Svelte sandbox - we komen zo bij React.

We beginnen met dezelfde webcomponent als voorheen en voegen een kleurkenmerk toe. Om onze webcomponent te configureren om een ​​attribuut te accepteren en erop te reageren, voegen we een static observedAttributes eigenschap die de kenmerken retourneert waarnaar onze webcomponent luistert.

static observedAttributes = ["color"];

Als dat op zijn plaats is, kunnen we een toevoegen attributeChangedCallback levenscyclusmethode, die wordt uitgevoerd wanneer een van de kenmerken die worden vermeld in observedAttributes zijn ingesteld of bijgewerkt.

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

Nu updaten we onze update methode om het daadwerkelijk te gebruiken:

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

Laten we als laatste onze . toevoegen increment eigendom:

increment = 1;

Eenvoudig en bescheiden.

De tellercomponent gebruiken in Svelte

Laten we gebruiken wat we net hebben gemaakt. We gaan naar onze Svelte app-component en voegen zoiets als dit toe:

<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>

En het werkt! Onze teller wordt weergegeven, verhoogd en de vervolgkeuzelijst werkt de kleur bij. Zoals u kunt zien, renderen we het kleurattribuut in onze Svelte-sjabloon en, wanneer de waarde verandert, neemt Svelte het werk van het bellen over setAttribute op onze onderliggende webcomponentinstantie. Er is hier niets bijzonders: dit is hetzelfde wat het al doet voor de attributen van elke HTML-element.

Dingen worden een beetje interessant met de increment steun. Dit is niet een attribuut op onze webcomponent; het is een prop in de klasse van de webcomponent. Dat betekent dat het moet worden ingesteld op de instantie van de webcomponent. Heb geduld met me, want de dingen zullen over een tijdje veel eenvoudiger worden.

Eerst zullen we enkele variabelen toevoegen aan onze Svelte-component:

let increment = 1;
let wcInstance;

Met onze krachtpatser van een tegencomponent kunt u met 1 of met 2 verhogen.

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

Maar in theorie, moeten we de daadwerkelijke instantie van onze webcomponent ophalen. Dit is hetzelfde wat we altijd doen wanneer we a . toevoegen ref met Reageren. Met Svelte is het eenvoudig bind:this richtlijn:

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

Nu luisteren we in onze Svelte-sjabloon naar wijzigingen in de increment-variabele van onze component en stellen we de onderliggende eigenschap van de webcomponent in.

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

Je kunt het uitproberen bij deze live demo.

We willen dit natuurlijk niet doen voor elke webcomponent of prop die we moeten beheren. Zou het niet leuk zijn als we gewoon konden setten increment direct op onze webcomponent, in opmaak, zoals we normaal doen voor componentrekwisieten, en heb het, weet je, gewoon werk? Met andere woorden, het zou leuk zijn als we alle vormen van gebruik van wcInstance en gebruik in plaats daarvan deze eenvoudigere code:

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

Het blijkt dat we dat kunnen. Deze code werkt; Svelte regelt al dat werk voor ons. Bekijk het in deze demo. Dit is standaardgedrag voor vrijwel alle JavaScript-frameworks.

Dus waarom heb ik je de handmatige manier getoond om de prop van de webcomponent in te stellen? Twee redenen: het is handig om te begrijpen hoe deze dingen werken en ik zei zojuist dat dit voor 'vrijwel' alle JavaScript-frameworks werkt. Maar er is één raamwerk dat gekmakend genoeg geen ondersteuning biedt voor het instellen van webcomponenten, zoals we zojuist hebben gezien.

Reageren is een ander beest

Interoperabele webcomponenten bouwen die zelfs werken met React PlatoBlockchain Data Intelligence. Verticaal zoeken. Ai.
Interoperabele webcomponenten bouwen die zelfs werken met React

Reageer. Het populairste JavaScript-framework ter wereld ondersteunt geen basisinteroperabiliteit met webcomponenten. Dit is een bekend probleem dat uniek is voor React. Interessant is dat dit is opgelost in de experimentele tak van React, maar om de een of andere reden niet is samengevoegd met versie 18. Dat gezegd hebbende, kunnen we nog steeds volg de voortgang ervan. En je kunt dit zelf proberen met een live demo.

De oplossing is natuurlijk om een ref, pak de instantie van de webcomponent en stel handmatig in increment wanneer die waarde verandert. Het ziet er zo uit:

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> );
}

Zoals we hebben besproken, is het eenvoudigweg niet schaalbaar om dit handmatig te coderen voor elke eigenschap van een webcomponent. Maar niet alles is verloren, want we hebben een aantal opties.

Optie 1: overal attributen gebruiken

We hebben attributen. Als je op de React-demo hierboven hebt geklikt, increment prop werkte niet, maar de kleur is correct veranderd. Kunnen we niet alles coderen met attributen? Helaas niet. Attribuutwaarden kunnen alleen tekenreeksen zijn. Dat is hier goed genoeg, en met deze aanpak zouden we een beetje ver kunnen komen. Cijfers zoals increment kan worden geconverteerd van en naar strings. We kunnen zelfs JSON-objecten stringify/parseren. Maar uiteindelijk zullen we een functie moeten doorgeven aan een webcomponent, en op dat moment zouden we geen opties meer hebben.

Optie 2: Wikkel het in

Er is een oud gezegde dat je elk probleem in de informatica kunt oplossen door een niveau van indirectheid toe te voegen (behalve het probleem van te veel niveaus van indirectheid). De code om deze rekwisieten in te stellen is vrij voorspelbaar en eenvoudig. Wat als we het in een bibliotheek verbergen? De slimme mensen achter Lit heb één oplossing:. Deze bibliotheek maakt een nieuwe React-component voor u nadat u deze een webcomponent hebt gegeven en de eigenschappen opsomt die nodig zijn. Hoewel slim, ben ik geen fan van deze aanpak.

In plaats van een één-op-één toewijzing van webcomponenten aan handmatig gemaakte React-componenten, heb ik liever gewoon: een Reageer component dat we onze webcomponent doorgeven tagnaam tot (counter-wc in ons geval) — samen met alle attributen en eigenschappen — en om deze component onze webcomponent weer te geven, voegt u de . toe ref, zoek dan uit wat een prop is en wat een attribuut is. Dat is in mijn ogen de ideale oplossing. Ik ken geen bibliotheek die dit doet, maar het zou eenvoudig moeten zijn om te maken. Laten we het een kans geven!

Dit is de gebruik Zochten naar:

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

wcTag is de tagnaam van de webcomponent; de rest zijn de eigenschappen en attributen die we willen doorgeven.

Zo ziet mijn implementatie eruit:

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);

De meest interessante regel is aan het einde:

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

Zo creëren we in React een element met een dynamische naam. In feite is dit waar React normaal gesproken JSX in transpileert. Al onze div's worden geconverteerd naar createElement("div") belt. Normaal gesproken hoeven we deze API niet rechtstreeks aan te roepen, maar hij is er wanneer we hem nodig hebben.

Verder willen we een lay-outeffect uitvoeren en door elke prop lopen die we aan onze component hebben doorgegeven. We doorlopen ze allemaal en controleren of het een woning is met een in check die het instantieobject van de webcomponent controleert, evenals de prototypeketen, die alle getters/setters die op het prototype van de klasse terechtkomen, zal opvangen. Als een dergelijke eigenschap niet bestaat, wordt aangenomen dat het een attribuut is. In beide gevallen stellen we het alleen in als de waarde daadwerkelijk is gewijzigd.

Als je je afvraagt ​​waarom we gebruiken useLayoutEffect in plaats van useEffect, is omdat we deze updates onmiddellijk willen uitvoeren voordat onze inhoud wordt weergegeven. Merk ook op dat we geen afhankelijkheidsreeks hebben voor onze useLayoutEffect; dit betekent dat we deze update willen uitvoeren op elke weergave. Dit kan riskant zijn omdat React de neiging heeft om opnieuw te renderen veel. Ik verbeter dit door het geheel in te pakken React.memo. Dit is in wezen de moderne versie van React.PureComponent, wat betekent dat het onderdeel alleen opnieuw wordt weergegeven als een van de werkelijke rekwisieten is gewijzigd - en het controleert of dat is gebeurd via een eenvoudige gelijkheidscontrole.

Het enige risico hier is dat als u een objectprop doorgeeft die u direct muteert zonder opnieuw toe te wijzen, u de updates niet zult zien. Maar dit wordt ten zeerste afgeraden, vooral in de React-gemeenschap, dus ik zou me er geen zorgen over maken.

Voordat ik verder ga, wil ik nog één ding noemen. U bent misschien niet blij met hoe het gebruik eruitziet. Nogmaals, dit onderdeel wordt als volgt gebruikt:

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

In het bijzonder vindt u het misschien niet leuk om de tagnaam van de webcomponent door te geven aan de <WcWrapper> component en geef in plaats daarvan de voorkeur aan de @lit-labs/react pakket hierboven, waarmee voor elke webcomponent een nieuwe individuele React-component wordt gemaakt. Dat is volkomen eerlijk en ik zou je willen aanmoedigen om te gebruiken waar je je het prettigst bij voelt. Maar voor mij is een voordeel van deze aanpak dat het gemakkelijk is om verwijderen. Als door een of ander wonder React de juiste verwerking van webcomponenten van hun experimentele tak samenvoegt in main morgen zou je de bovenstaande code hiervan kunnen veranderen:

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

…naar dit:

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

Je zou waarschijnlijk zelfs een enkele codemod kunnen schrijven om dat overal te doen, en dan verwijderen <WcWrapper> allemaal samen. Eigenlijk, schrap dat: een globaal zoeken en vervangen met een RegEx zou waarschijnlijk werken.

De implementatie

Ik weet het, het lijkt alsof het een reis heeft gekost om hier te komen. Als je je nog herinnert, was ons oorspronkelijke doel om de voorbeeldcode van de afbeelding te gebruiken die we in mijn . hebben bekeken laad-bericht, en verplaats het naar een webcomponent zodat het in elk JavaScript-framework kan worden gebruikt. Het gebrek aan goede interoperabiliteit van React voegde veel details toe aan de mix. Maar nu we een behoorlijke greep hebben op hoe we een webcomponent moeten maken en gebruiken, zal de implementatie bijna een anticlimax zijn.

Ik laat de hele webcomponent hier vallen en noem enkele van de interessante stukjes. Als je het in actie wilt zien, hier is een werkende demo. Het schakelt tussen mijn drie favoriete boeken over mijn drie favoriete programmeertalen. De URL voor elk boek is elke keer uniek, dus je kunt het voorbeeld zien, hoewel je waarschijnlijk dingen in je DevTools-netwerktabblad wilt vertragen om echt te zien wat er gebeurt.

Volledige code bekijken
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); }
}

Eerst registreren we het kenmerk waarin we geïnteresseerd zijn en reageren wanneer het verandert:

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

Dit zorgt ervoor dat onze afbeeldingscomponent wordt gemaakt, die alleen wordt weergegeven wanneer deze is geladen:

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;
}

Vervolgens hebben we onze preview-eigenschap, die ofwel onze base64 preview-string kan zijn, of onze blurhash pakket:

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

Dit is afhankelijk van de hulpfunctie die we nodig hebben:

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;
}

En als laatste onze render methode:

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

En een paar hulpmethoden om alles aan elkaar te knopen:

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); }
}

Het is een beetje meer boilerplate dan we nodig zouden hebben als we dit in een raamwerk bouwen, maar het voordeel is dat we dit kunnen hergebruiken in elk raamwerk dat we willen - hoewel React voorlopig een wrapper nodig heeft, zoals we hebben besproken .

Kansen en eindigt

Ik heb Lit's React-wrapper al genoemd. Maar als je merkt dat je Stencil gebruikt, ondersteunt het eigenlijk een aparte uitvoerpijplijn alleen voor React. En de goede mensen bij Microsoft hebben ook heeft iets gemaakt dat lijkt op Lit's wrapper, gekoppeld aan de Fast-webcomponentbibliotheek.

Zoals ik al zei, zullen alle frameworks die niet de naam React hebben, het instellen van webcomponenteigenschappen voor u afhandelen. Houd er rekening mee dat sommige een aantal speciale smaken van syntaxis hebben. Met Solid.js bijvoorbeeld, <your-wc value={12}> gaat er altijd vanuit dat value is een eigenschap die u kunt overschrijven met een attr voorvoegsel, zoals <your-wc attr:value={12}>.

Afsluiten

Webcomponenten zijn een interessant, vaak onderbenut onderdeel van het webontwikkelingslandschap. Ze kunnen u helpen uw afhankelijkheid van een enkel JavaScript-framework te verminderen door uw gebruikersinterface of "blad"-componenten te beheren. Hoewel het maken van deze als webcomponenten - in tegenstelling tot Svelte of React-componenten - niet zo ergonomisch zal zijn, is het voordeel dat ze op grote schaal herbruikbaar zullen zijn.


Interoperabele webcomponenten bouwen die zelfs werken met React oorspronkelijk gepubliceerd op CSS-trucs. Je zou moeten ontvang de nieuwsbrief.

Tijdstempel:

Meer van CSS-trucs