Les Web Components
Face au désordre du js impératif qu'on a vu précédemment, les navigateurs ont intégré une solution native : les Web Components.
L'objectif est d'encapsuler la structure HTML, le style CSS et la logique JS dans une balise personnalisée réutilisable (un custom element). Au lieu d'avoir un gros fichier avec tous nos querySelector, on divise notre interface en petits blocs indépendants.
Pour créer un web component, on utilise une class JS qui hérite de HTMLElement et on utilise le shadow dom pour isoler le composant du reste de la page.
class MyButton extends HTMLElement {
constructor() {
super();
/* On attache un shadow dom pour isoler le style et le html */
this.attachShadow({ mode: 'open' });
/* On injecte le contenu de notre composant */
this.shadowRoot.innerHTML = `
<style>
button { background: blue; color: white; border-radius: 4px; }
</style>
<button>cliquez-moi</button>
`;
}
}
/* On enregistre notre nouvelle balise html personnalisée */
customElements.define('my-button', MyButton);Une fois déclaré, on peut utiliser <my-button></my-button> directement dans notre html.
C'est très bien pour créer des design systems agnostiques (qui marchent partout). Mais est-ce que ça résout notre problème de gestion d'état ?
Non. Le composant est isolé. Si un clic à l'intérieur du composant doit mettre à jour un compteur global situé à l'extérieur, on doit utiliser des événements personnalisés (CustomEvent) et la synchronisation reste fastidieuse.
Exercice
Reprenez la carte produit de l'exercice précédent et transformez-la en un web component autonome nommé <product-card>.
Dans cet exercice, vous devrez :
- créer une classe
ProductCardétendantHTMLElement - déplacer le html et le css de la carte produit dans le
shadowRootde ce composant - déclarer le custom element
product-cardet remplacer le html de base par votre nouvelle balise<product-card></product-card> - essayer de mettre à jour le compteur global du panier (situé dans le header en dehors du composant) lors du clic sur le bouton d'ajout interne
Pour communiquer vers l'extérieur depuis un shadow dom, vous aurez sûrement besoin de this.dispatchEvent(...).