Les Composants Web sont constitués de plusieurs technologies distinctes permettant de créer des composants d'interface graphique personnalisés et réutilisables, qui ont été créés en utilisant des technologies web libres. Ils font partie du navigateur, et donc ne nécessitent pas de bibliothèque externe comme jQuery ou Dojo. Un Composant Web existant peut être utilisé sans l'écriture de code, en ajoutant simplement une déclaration d'importation à une page HTML. Les Composants Web utilisent les nouvelles capacités standard de navigateur, ou celles en cours de développement.
Custom Element
La première partie des web component est la possibilité de créer des éléments HTML personnalisés.
export default class SecondTimer extends HTMLElement {
static get observedAttributes() { return ['prefix']; }
constructor () {
super()
this.i = 0
this.span = document.createElement('span')
this.span.classList.add('badge')
this.span.classList.add('badge-secondary')
this.span.innerHTML = this.i
this.$prefix = document.createElement('span')
this.appendChild(this.$prefix)
this.appendChild(this.span)
}
connectedCallback () {
this.timer = window.setInterval(() => {
this.i++
this.span.innerHTML = this.i
}, 1000)
}
disconnectedCallback () {
clearInterval(this.timer)
}
attributeChangedCallback (name, oldValue, newValue) {
if (name === 'prefix' && oldValue !== newValue) {
this.$prefix.innerHTML = newValue + " : "
}
}
}
Une fois cet élément déclaré il sera possible de l'utiliser pour définir un composant.
customElements.define('second-timer', SecondTimer)
Maintenant il sera possible d'utiliser notre élément HTML
<div class="container" style="margin-top: 60px;">
<second-timer prefix="Compteur">
</div>
Vous pouvez aussi déclarer un élément qui hérite d'un élément HTML natif. Par exemple si on souhaite convertir un champs texte en datepicker simplement :
export default class Datepicker extends HTMLInputElement {
connectedCallback () {
this.calendar = flatpickr(this)
}
disconnectedCallback () {
this.calendar.destroy()
}
}
customElements.define('date-picker', Datepicker, {extends: 'input'})
Vous pourrez ensuite l'utiliser sur les champs à l'aide de l'attribute is
<input name="demo" is="date-picker" type="text">
Cette seconde méthode peut être pratique pour ajouter des comportements spécifiques à certains éléments sans redéfinir une structure.
Le shadow dom
Un aspect important des composants est la capacité de garder la structure, le style et le comportement isolé du reste de l'application. L'API Shadow DOM permet d'attacher un élément DOM caché à un élément (ici notre composant).
export default class MyButton extends HTMLElement {
constructor () {
super()
this.shadow = this.attachShadow({mode: 'closed'})
this.shadow.innerHTML = `<style>
:host {
--bg: #000;
}
button {
border:none;
background: var(--bg);
color: #FFF;
border-radius: 3px;
padding:3px 10px;
}
</style>
<slot></slot>
<button><slot name="inbutton"/></button>`
}
}
La méthode Element.attachShadow()
permet de créer un nouvel arbre shadow DOM et l'attache à l'élément spécifié. Cette arbre sera isolé du reste de la page, ce qui signifie plusieurs choses :
- Le style de la page n'affecte pas les éléments situé dans l'arbre shadow DOM.
- Le style définit dans l'arbre shadow DOW n'affecte pas le reste de la page.
- Le JavaScript ne peut pas accéder aux éléments à l'intérieur de l'arbre DOM si l'arbre a été créé avec le mode
closed
.
Vous avez aussi la possibiliter d'utiliser des <slot>
qui permettent de récupérer les éléments à l'intérieur du composant.
<my-button>Ce contenu sera injecté dans le slot</my-button>
Il est aussi possible d'avoir plusieurs slots nommés
<my-card>
<div slot="header">Je serais injecté dans le slot avec name="header"</div>
<div slot="body">Et moi dans le name="body" !</div>
</my-card>