Avanserte Verktøy for Web Components

0
31

I løpet av de siste fire artikler i denne fem-del-serien, vi har tatt en bred se på teknologier som utgjør Web Components standarder. Først så vi på hvordan å lage HTML-maler som kan brukes på et senere tidspunkt. For det andre, vi stupte inn til å skape vår egen tilpasset element. Etter at vi sammenfattet våre element er stiler og velgere i skyggen DOM, slik at våre element er helt selvstendig.

Vi har undersøkt hvordan disse kraftige verktøy kan være med å skape vår egen tilpasset sperrende dialogboks, som er et element som kan brukes i de fleste moderne programmet sammenhenger uavhengig av underliggende rammeverk eller biblioteket. I denne artikkelen vil vi se på hvordan du bruker våre element i de ulike rammer og se på noen avanserte verktøy for å virkelig bygge opp din Web-Komponent ferdigheter.

Artikkel-Serien:

  1. En Introduksjon til Web Components
  2. Lage Gjenbrukbare HTML-Maler
  3. Opprette en Egendefinert Element fra Scratch
  4. Omfatter Stil og Struktur med Skygge DOM
  5. Avanserte Verktøy for Web Components (Dette innlegget)

Rammeverket agnostisk

Vår dialog komponent fungerer bra i nesten alle framework eller selv uten. (Gitt, hvis JavaScript er deaktivert, det hele er bortkastet.) Kantete og Vue behandle Web Components som første-klasse borgere: de rammer som har blitt designet med web-standarder i tankene. Reagerer litt mer sta, men ikke umulig å integrere.

Kantete

Først, la oss ta en titt på hvordan Vinklet håndtak tilpassede elementer. Som standard, Kantete vil kaste en mal feil når den møter en element det ikke kjenner igjen (dvs. standard nettleser elementer eller noen av komponentene som er definert av Kantete). Dette kan endres ved å inkludere CUSTOM_ELEMENTS_SCHEMA.

…gir en NgModule til å inneholde følgende:

  • Ikke-Kantete elementer navngitt med dash-saken (-).
  • Element egenskaper navn med bindestrek tilfelle (-). Dash tilfelle er navnekonvensjonen for tilpassede elementer.

— Kantete Dokumentasjon

Tidkrevende dette skjemaet er like enkelt som å legge den til som en modul:

import { NgModule, CUSTOM_ELEMENTS_SCHEMA } fra ‘@kantete/core’;

@NgModule({
/** Utelatt */
skjemaene: [ CUSTOM_ELEMENTS_SCHEMA ]
})
eksport klasse MyModuleAllowsCustomElements {}

Det er det. Etter dette, Kantete vil tillate oss å bruke våre tilpasset element hvor vi vil med standard eiendom og event bindinger:

<en-dialog [åpne]=”isDialogOpen” (dialog-lukket)=”dialogClosed($event)”>
<span spilleautomat=”overskrift”>Overskrift tekst</span>
<div>
<p>Kroppen kopi</p>
</div>
</one-dialogboksen>
Vue

Vue kompatibilitet med Web Components er enda bedre enn Kantete er som det ikke krever noen spesiell konfigurering. Når et element er registrert, kan den brukes med Vue ‘ s standard templating syntaks:

<one-dialogboksen v-bind:open=”isDialogOpen” v-på:dialog-lukket=”dialogClosed”>
<span spilleautomat=”overskrift”>Overskrift tekst</span>
<div>
<p>Kroppen kopi</p>
</div>
</one-dialogboksen>

En påminnelse med Kantete og Vue, imidlertid, er deres standard skjema kontrollene. Hvis vi ønsker å bruke noe som reaktive former eller [(ng-modell)] i Kantete eller v-modellen i Vue på et tilpasset element med en form kontroll, må vi sette opp at avløp som er utenfor omfanget av denne artikkelen.

Reagerer

Reagerer er litt mer komplisert enn Kantete. Reagerer virtual DOM effektivt tar en JSX treet og gjør det som et stort objekt. Så, i stedet for direkte å endre attributter på HTML-elementer som Kantete eller Vue, Reagerer bruker et objekt syntaks til å spore endringer som må gjøres til DOM og oppdaterer dem i bulk. Dette fungerer helt fint i de fleste tilfeller. Våre dialogboksen åpne attributtet er bundet til sin eiendom og vil svare godt til å endre rekvisitter.

Fangsten kommer når vi begynner å se på CustomEvent sendt når våre dialogboksen lukkes. Reagerer implementerer en rekke native-event lyttere for oss med sin syntetiske event system. Dessverre, som betyr at kontrollene som onDialogClosed vant faktisk ikke fest event lyttere til vår komponent, så vi må finne på noen annen måte.

Den mest åpenbare hjelp av å legge til egendefinerte hendelsen lyttere i Reagerer på er ved hjelp av DOM-refs. I denne modellen, vi kan henvise til våre HTML-node direkte. Syntaksen er litt detaljert, men fungerer bra:

import Reagere, { Komponent, createRef } fra “reagerer’;

eksport standard klasse MyComponent strekker seg Komponent {
constructor(props) {
super(props);
// Opprette ref
dette.dialogboksen = createRef();
// Binde vår metode for eksempel
dette.onDialogClosed = dette.onDialogClosed.bind(this);

dette.tilstand = {
åpne: false
};
}

componentDidMount() {
// Når komponent hauger, legg til hendelsen listener
dette.dialogboksen.gjeldende.addEventListener (‘- dialogen lukket”.onDialogClosed);
}

componentWillUnmount() {
// Når komponent unmounts, ta lytteren
dette.dialogboksen.gjeldende.removeEventListener (‘- dialogen lukket”.onDialogClosed);
}

onDialogClosed(hendelse) { /** Utelatt **/ }

render() {
retur <div>
<one-dialogboksen åpne={dette.staten.åpne} ref={dette.dialogboksen}>
<span spilleautomat=”overskrift”>Overskrift tekst</span>
<div>
<p>Kroppen kopi</p>
</div>
</one-dialogboksen>
</div>
}
}

Eller, vi kan bruke statsløse funksjonelle komponenter og kroker:

import Reagere, { useState, useEffect, useRef } fra “reagerer’;

eksport standard funksjon MyComponent(props) {
const [ dialogOpen, setDialogOpen ] = useState(false);
const oneDialog = useRef(null);
const onDialogClosed = event => konsollen.logg(event);

useEffect(() => {
oneDialog.gjeldende.addEventListener (‘- dialogen-stengt’, onDialogClosed);
retur () => oneDialog.gjeldende.removeEventListener (‘- dialogen-stengt’, onDialogClosed)
});

retur <div>
<- knappen for onClick={() => setDialogOpen(true)}>Åpne dialogboksen</button>
<one-dialogboksen ref={oneDialog} open={dialogOpen}>
<span spilleautomat=”overskrift”>Overskrift tekst</span>
<div>
<p>Kroppen kopi</p>
</div>
</one-dialogboksen>
</div>
}

Det er ikke dårlig, men du kan se hvordan gjenbruk av denne komponenten kan fort bli tungvint. Heldigvis, kan vi eksportere en standard Reagere komponent som omslutter vår tilpassede elementet ved hjelp av de samme verktøyene.

import Reagere, { Komponent, createRef } fra “reagerer’;
import PropTypes fra ‘prop-typer’;

eksport standard klasse OneDialog strekker seg Komponent {
constructor(props) {
super(props);
// Opprette ref
dette.dialogboksen = createRef();
// Binde vår metode for eksempel
dette.onDialogClosed = dette.onDialogClosed.bind(this);
}

componentDidMount() {
// Når komponent hauger, legg til hendelsen listener
dette.dialogboksen.gjeldende.addEventListener (‘- dialogen lukket”.onDialogClosed);
}

componentWillUnmount() {
// Når komponent unmounts, ta lytteren
dette.dialogboksen.gjeldende.removeEventListener (‘- dialogen lukket”.onDialogClosed);
}

onDialogClosed(hendelse) {
// Sjekk for å sikre at støtten er til stede før du ringer det
hvis (denne.rekvisitter.onDialogClosed) {
dette.rekvisitter.onDialogClosed(event);
}
}

render() {
const { barn, onDialogClosed, …rekvisitter } = dette.rekvisitter;
retur <en-dialog {…rekvisitter} ref={dette.dialogboksen}>
{barna}
</one-dialogboksen>
}
}

OneDialog.propTypes = {
barn: barn: PropTypes.oneOfType([
PropTypes.arrayOf(PropTypes.node),
PropTypes.node
]).isRequired,
onDialogClosed: PropTypes.func
};

…eller igjen som en statsløs, funksjonell komponent:

import Reagere, { useRef, useEffect } fra “reagerer’;
import PropTypes fra ‘prop-typer’;

eksport standard funksjon OneDialog(props) {
const { barn, onDialogClosed, …restProps } = rekvisitter;
const oneDialog = useRef(null);

useEffect(() => {
onDialogClosed ? oneDialog.gjeldende.addEventListener (‘- dialogen-stengt’, onDialogClosed) : null;
retur () => {
onDialogClosed ? oneDialog.gjeldende.removeEventListener (‘- dialogen-stengt’, onDialogClosed) : null;
};
});

retur <en-dialog ref={oneDialog} {…restProps}>{barna}</one-dialogboksen>
}

Nå kan vi bruke vår dialog innebygd i Reagerer, men fortsatt beholde den samme API-på tvers av alle våre programmer (og fortsatt slippe klasser, hvis det er din greie).

import Reagere, { useState } fra “reagerer’;
import OneDialog fra ‘./OneDialog’;

eksport standard funksjon MyComponent(props) {
const [åpne, setOpen] = useState(false);
retur <div>
<- knappen for onClick={() => setOpen(true)}>Åpne dialogboksen</button>
<OneDialog open={åpne} onDialogClosed={() => setOpen(false)}>
<span spilleautomat=”overskrift”>Overskrift tekst</span>
<div>
<p>Kroppen kopi</p>
</div>
</OneDialog>
</div>
}

Avanserte verktøy

Det finnes en rekke gode verktøy for redigering av dine egne elementer. Du søker gjennom npm avslører et mangfold av verktøy for å lage svært reaktive tilpassede elementer (inkludert min egen pet project), men den mest populære i dag langt er tent, html fra Polymer team og, mer spesifikt for Web Components, LitElement.

LitElement er en tilpassede elementer base klasse som gir en serie av Api-ene for å gjøre alle de tingene vi har gått gjennom så langt. Det kan kjøres i en nettleser uten en bygge trinn, men hvis du liker ved hjelp av fremtidsrettet verktøy som dekoratører, det er verktøy for at så vel.

Før dykking i hvordan å bruke tent, eller LitElement, ta et minutt til å gjøre deg kjent med merket mal verdiane, som er en spesiell type av funksjon som kalles opp på malen bokstavelig strenger i JavaScript. Disse funksjonene ta i et array med strenger, og en samling av interpolerte verdier og kan gå tilbake alt du måtte ønske.

funksjonen tag(strenger, …verdier) {
– konsollen.logg({ strenger, verdier });
return true;
}
const som = ‘verden’;

tag ‘ hei, ${hvem}`;
/** ville logg ut { strenger: [“hei”, “], verdier: [‘verden’] } og returnere sann **/

Hva LitElement gir oss et levende, dynamisk oppdatering av alt gått til at verdier array, slik som en eiendel oppdateringer, elementets gjengi funksjon ville bli kalt, og den resulterende DOM ville bli re-rendret

import { LitElement, html } fra “tent-element’;

klasse SomeComponent {
statisk få egenskaper() {
tilbake {
nå: { type: String }
};
}

connectedCallback() {
// Sørg for å ringe super
super.connectedCallback();
dette.intervall = vinduet.setInterval(() => {
dette.nå = Dato.nå();
});
}

disconnectedCallback() {
super.disconnectedCallback();
vinduet.clearInterval(denne.intervall);
}

render() {
tilbake html`<h1>Det er ${dette.nå}</h1>`;
}
}

customElements.define(‘noen-komponent’, SomeComponent);

Se Penn
LitElement nå for eksempel ved Caleb Williams (@calebdwilliams)
på CodePen.

Det du vil merke er at vi er nødt til å definere noen eiendom ønsker vi LitElement å se hjelp av det statiske egenskaper getter. Ved hjelp av at API forteller base klasse å ringe gjengi når en endring er gjort til komponent egenskaper. render, i sin tur, vil bare oppdatere de nodene som har behov for å endre.

Så, for vår dialog eksempel, ville det se ut som dette ved hjelp av LitElement:

Se Penn
Dialogboksen for eksempel ved hjelp av LitElement av Caleb Williams (@calebdwilliams)
på CodePen.

Det er flere varianter av tente-html tilgjengelig, inkludert Hjemsøkt, Reagerer kroker-stil bibliotek for Web-Komponenter som kan også gjøre bruk av virtuelle komponenter ved hjelp tent-html som en base.

På slutten av dagen, de fleste av moderne Web-Komponenter verktøy er ulike varianter av hva LitElement er: en base klasse som abstracts felles logikk bort fra våre komponenter. Blant de andre smakene er Sjablong, SkateJS, Kantete Elementer og Polymer.

Hva er neste

Web-Komponenter, standarder fortsetter å utvikle seg og nye funksjoner blir diskutert og lagt til nettlesere på en kontinuerlig basis. Snart, Web-Komponenten, forfattere vil ha Api for å kommunisere med web former på et høyt nivå (inkludert andre element internals som er utenfor omfanget av disse innledende artikler), som opprinnelige HTML-og CSS-modul import, native mal oppretting og oppdatering av kontrollene, og mange flere som kan spores på W3C/web components problemer bord på GitHub.

Disse standardene er klar til å vedta inn i våre prosjekter i dag med det aktuelle polyfills for eldre nettlesere og Edge. Og mens de kan ikke erstatte rammen av valg, de kan brukes sammen med dem for å styrke deg og din organisasjon arbeidsflyter.