Les composants Web sont un ensemble de normes définissant les interfaces logicielles pour l'organisation de l'architecture des composants. Tous sont mis en œuvre dans les versions modernes des navigateurs, c'est-à-dire ils ne nécessitent pas de connexion de bibliothèques ou de transpilateurs de code, cependant, si vous avez besoin de compatibilité, par exemple, avec Internet Explorer 11, vous devrez probablement encore utiliser des bibliothèques et des transpilers.
Cet article est destiné au niveau initial de formation et aux développeurs qui ont de l'expérience avec l'un ou l'autre framework front-end, mais peut-être, grâce à quelques astuces, il sera intéressant pour les experts expérimentés.
Toutes les expériences citées ci-dessous ont été testées dans Chrome et Firefox n'est peut-être même pas la version la plus récente.
Commençons donc.
Créez d'abord un répertoire pour le projet et accédez-y.
mkdir mywebcomp cd mywebcomp
Exécuter:
npm init
dans ce répertoire en répondant à toutes les questions par défaut.
Créez un fichier
index.html avec le contenu le plus simple du répertoire.
<html lang="en"> <body> </body> </html>
Ajoutez une balise pour un élément, le nom doit contenir un trait d'union, c'est un signal pour le sous-système CusomElements pour essayer de définir cet élément comme s'appuyant sur les éléments standard.
<html lang="en"> <body> <my-webcomp></my-webcomp> </body> </html>
Ajoutez une classe de gestionnaire à la balise de
script .
<script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { this.insertAdjacentHTML('beforeEnd', `<div>Hello</div>`) } } customElements.define('my-webcomp', MyWebComp); </script>
Dans la balise de
script modulaire, nous avons défini une nouvelle classe qui, à l'aide de la méthode
customElements.define () , l'a définie derrière la
balise my-webcomp . Et en ajoutant le code à la méthode
connectedCallback () , nous avons fourni son appel lors de l'ajout de l'implémentation du composant à l'arborescence. Le résultat peut déjà être consulté dans le navigateur:

Cependant, placer la mise en page HTML directement dans le code, si cela est pratique pour les petits morceaux, n'est généralement pas correct, ce qui est particulièrement vrai lorsque les morceaux atteignent une taille décente. Par exemple, sur un formulaire à 20 éléments, que battre sur des sous-composants peut également ne pas toujours être pratique. Par conséquent, pour commencer, nous allons disposer la mise en page dans le modèle, qui sera situé dans le même html, bien que rien ne nous empêche de le charger à partir d'un fichier séparé si nécessaire.
<html lang="en"> <body> <template id="myWebCompTemplate"> <div>Hello</div> </template> <my-webcomp></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let tplEl = document.querySelector('#myWebCompTemplate'); let html = document.importNode(tplEl.content, true); this.appendChild(html); } } customElements.define('my-webcomp', MyWebComp); </script> </body> </html>
Dans le code du composant, nous avons remplacé l'insertion d'une chaîne par html en recevant un élément de modèle par id. Importer i.e. créer une copie de cet élément et créer un lien vers le contenu de l'élément en cours.
id est nommé en notation camelCase depuis tous les identificateurs d'éléments sont jetés dans l'espace de noms global lors de l'utilisation de tirets ou d'autres spéciaux. les personnages qui y accèdent peuvent être moins élégants. C'est-à-dire on pourrait plutôt:
let tplEl = document.querySelector('#myWebCompTemplate'); let html = document.importNode(tplEl.content, true);
écrivez sur une seule ligne:
let html = document.importNode(myWebCompTemplate.content, true);
et ce code fonctionnerait de la même manière, mais il est considéré comme peu sûr. De plus, si nous attribuons un identifiant à notre élément, nous pouvons y accéder de n'importe où dans le contexte en tant qu'instance à partir de l'espace de noms global en appelant des méthodes et en obtenant des valeurs de propriété.
Par exemple, comme ceci:
<my-webcomp id="myWebComp"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } } customElements.define('my-webcomp', MyWebComp); </script> <script type="module"> myWebComp.showMessage(); </script>
Dans ce scénario, l'alerte sera affichée immédiatement au chargement de la page.
Nous allons maintenant bloquer un gestionnaire de clic de souris pour notre composant qui affichera un message d’alerte.
<my-webcomp id="myWebComp" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } showMessage(event) { alert("This is the message"); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script>
Maintenant, lorsque vous cliquez sur un message, nous réagissons aux actions des utilisateurs.

L'argument de la méthode
showMessage () déclare également un objet
événement qui stocke des données d'événement, telles que les coordonnées d'un clic ou un lien vers l'élément lui-même.
Souvent, chaque élément particulier doit être configuré d'une manière unique pour cela, cela peut être fait en utilisant des attributs.
Ajoutez une deuxième instance de l'élément et définissez pour chacune d'entre elles différentes propriétés de
nom de bienvenue dont les valeurs seront affichées lorsque l'élément sera cliqué.
<my-webcomp id="myWebComp" greet-name="John" onclick="this.showMessage(event)"></my-webcomp> <my-webcomp id="myWebComp2" greet-name="Josh" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script>
Maintenant, lorsque vous cliquez sur le premier, "Ceci est le message pour John" sera affiché, et sur le second, "Ceci est le message pour Josh".
Il peut arriver que l'attribut doive être utilisé non pas dans le traitement des événements, mais directement rendu dans le modèle, pour cela, nous ajouterons id à l'élément cible et substituerons la valeur de api immédiatement après avoir rendu une copie de l'objet modèle.
<template id="myWebCompTemplate"> <div id="helloLabel">Hello</div> </template> <my-webcomp id="myWebComp" greet-name="John" onclick="this.showMessage(event)"></my-webcomp> <my-webcomp id="myWebComp2" greet-name="Josh" onclick="this.showMessage(event)"></my-webcomp> <script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.appendChild(html); this.querySelector('#helloLabel').textContent += ' ' + this.getAttribute('greet-name'); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script>
Il se présente comme ceci:

Au lieu de
.textContent, il peut s'agir de
.innerHTML ou vous pouvez appeler la même méthode
.insertAdjacentHTML () sur l'objet à partir du sélecteur que nous avons fait au tout début.
Pendant longtemps, l'utilisation des identifiants a été considérée comme une mauvaise forme, car sur des quantités importantes de code, ils pouvaient être dupliqués, ce qui entraînait des collisions. Cependant, avec l'avènement de la technologie d'arbre fantôme, vous pouvez isoler sans crainte le contenu interne d'un élément à l'aide d'identificateurs, de styles et d'autres ressources. Pour les composants Web, l'arborescence des ombres est activée comme suit:
this.attachShadow({mode: 'open'});
Maintenant, la vérité est que tous les appels DOM à ceci devront être remplacés par
this.shadowRoot, car ils ne sont pas si nombreux.
<script type="module"> class MyWebComp extends HTMLElement { connectedCallback() { let html = document.importNode(myWebCompTemplate.content, true); this.attachShadow({mode: 'open'}); this.shadowRoot.appendChild(html); this.shadowRoot.querySelector('#helloLabel').textContent += ' ' + this.getAttribute('greet-name'); } showMessage(event) { alert("This is the message " + this.getAttribute('greet-name')); console.log(event); } } customElements.define('my-webcomp', MyWebComp); </script>
Visuellement, le travail de ce code ne changera plus en aucune façon, mais maintenant il n'y aura plus de helloLabel dans l'espace de noms global, et la page a déjà 2 éléments avec cet identifiant. Et vous pouvez y accéder, par exemple, comme ceci:
myWebComp.shadowRoot.getElementById('helloLabel');
puis si vous ne fermez pas l'arborescence en passant l'attribut correspondant dans la méthode
.attachShadow () .
Nous avons obtenu beaucoup de code et le placer directement dans le fichier html n'est pas non plus très correct. Par conséquent, nous allons créer le
fichier my-webcomp.js et y transférer notre classe avec l'instruction d'exportation, et ajouter l'importation de cette classe dans la balise de script pour obtenir ceci:
<script type="module"> import { MyWebComp } from "./my-webcomp.js"; customElements.define('my-webcomp', MyWebComp); myWebComp.shadowRoot.getElementById('helloLabel'); </script>
Cela n'affectera pas les performances, mais maintenant toute notre logique métier est séparée en .js, la configuration est effectuée dans des attributs html et les systèmes de navigation modulaire et composant prennent en charge l'initialisation asynchrone modulaire.
Cependant, à partir de maintenant, ouvrir
index.html en tant que local pour le développement échouera, car le navigateur bloquera le téléchargement du script depuis le système de fichiers. Si vous avez nodejs, vous pouvez mettre le serveur Web le plus simple:
npm i http-server -g
et l'exécuter avec la commande http-server dans le répertoire du projet, au démarrage, il indiquera l'hôte et le port à partir duquel vous pouvez ouvrir la page
http://127.0.0.1:8080
Ce sera désormais l'adresse de la page de débogage avec notre élément.
L'écriture de tests est également importante pour le développement; ils aident à garder le code fonctionnel pendant le développement de ses composants. Pour tester les composants Web, vous pouvez utiliser mocha en mode de lancement à partir du navigateur.
Ajoutez des packages.
npm i mocha chai wct-mocha --save-dev
Pour ce faire, créez le répertoire de
test et ajoutez-y le fichier
all.html suivant :
<!doctype html> <html> <head> <meta charset="utf-8"> <script src="../node_modules/mocha/mocha.js"></script> <script src="../node_modules/chai/chai.js"></script> <script src="../node_modules/wct-mocha/wct-mocha.js"></script> </head> <body> <script> WCT.loadSuites([ 'my-webcomp.tests.html', ]); </script> </body> </html>
Copiez notre
index.html pour
tester / lui donner le nom
my-webcomp.tests.html et ajoutez le même contenu de tête que dans
all.html .
Cependant, nous devrons maintenant remplacer l'initialisation et les manipulations habituelles par celles effectuées dans le cadre du test:
<script type="module"> import { MyWebComp } from "../my-webcomp.js"; customElements.define('my-webcomp', MyWebComp); suite('MyWebComp', () => { test('is MyWebComp', () => { const element = document.getElementById('myWebComp'); chai.assert.instanceOf(element, MyWebComp); }); }); </script>
Maintenant en entrant
http://127.0.0.1:8080/test/all.html
Un rapport de test sera affiché.

Mais vous devrez peut-être exécuter les tests automatiquement et dans différents navigateurs, vous devrez installer un utilitaire spécial:
sudo npm install --global web-component-tester --unsafe-perm
et courir comme ceci:
wct --npm
Cette ligne peut être ajoutée à la section
test du fichier
package.json et s'exécuter en tant que:
npm test

Il est recommandé de tester chaque méthode de classe significative dans le cadre d'un test distinct. Si vous souhaitez effectuer une initialisation commune pour chacun, vous devez la définir dans la méthode
suiteSetup () :
suiteSetup(() => { });
à l'intérieur de la suite.
C'est probablement suffisant pour la première fois, nous avons obtenu un projet minimal que s'il résolvait une tâche spécifique, il n'aurait pas honte de le faire.
npm publish
ou au moins
git push
Il n'y a pas encore beaucoup de livres sur le sujet, mais toute la documentation complète se trouve facilement selon les composants Web, CustomElements, ShadowDOM, balise de modèle natif, événements personnalisés.
Vous pouvez vérifier votre code avec le référentiel:
https://bitbucket.org/techminded/mywebcompUne suite du sujet montrant comment interagir entre les composants via l'utilisation d'événements peut être trouvée
ici.