Possiamo creare elementi HTML personalizzati, dichiarati e descritti tramite delle apposite classi, ognuno con i suoi metodi, proprietà, eventi e così via.
Una volta definito un elemento personalizzato, possiamo usarlo al pari di qualunque altro elemento HTML built-in.
Ciò è grandioso, essendo che il dizionario HTML è molto ricco, ma non infinito. Non ci sono <easy-tabs>, <sliding-carousel>, <beautiful-upload>…Ci basti pensare a qualunque altro tag di cui avremmo necessità.
Possiamo definirli con delle classi speciali, ed usarli come se fossero sempre stati parte dell’HTML.
Gli elementi personalizzati si dividono in due categorie:
- Elementi personalizzati autonomi – elementi “nuovi di zecca”, che estendono la classe astratta
HTMLElement. - Elementi built-in personalizzati – estendono gli elementi built-in, ad esempio un pulsante personalizzato, basato su
HTMLButtonElementetc.
Prima di tutto, affrontiamo gli elementi autonomi, dopodiché ci sposteremo a quelli built-in personalizzati.
Per creare un elemento personalizzato, abbiamo bisogno di comunicare al browser una serie di dettagli relativi: come mostrarlo, cosa fare una volta che l’elemento viene aggiunto o rimosso dalla pagina, etc.
Ciò viene fatto creando una classe con dei metodi appositi. È facile, dato che ci sono pochi metodi, tutti opzionali.
Ecco uno schema predefinito per la classe, con la lista completa:
class MyElement extends HTMLElement {
constructor() {
super();
// elemento creato
}
connectedCallback() {
// il browser chiama questo metodo quando l'elemento viene aggiunto al documento
// (può essere chiamato tante volte se un elemento viene raggiunto o rimosso)
}
disconnectedCallback() {
// il browser chiama questo metodo quando l'elemento viene rimosso dal documento
// (può essere chiamato tante volte se un elemento viene aggiunto o rimosso)
}
static get observedAttributes() {
return [/* un array di nomi di attributi per monitorare le modifiche */];
}
attributeChangedCallback(name, oldValue, newValue) {
// chiamato quando uno degli attributi della lista precedente viene modificato
}
adoptedCallback() {
// chiamato quando l'elemento viene spostato su un nuovo documento
// (avviene in document.adoptNode, usato molto raramente)
}
// possono esserci altri metodi e proprietà per l'elemento
}
Dopodiché, possiamo registrare l’elemento:
// fa in modo che il browser sappia che <my-element> viene fornito dalla nostra classe
customElements.define("my-element", MyElement);
Adesso, per ogni elemento HTML con tag <my-element>, verrà creata un’istanza di MyElement, e chiamati i sopracitati metodi. Possiamo anche chiamare document.createElement('my-element') in JavaScript.
-I nomi degli elementi personalizzati devono contenere un trattino -, ad esempio my-element e super-button sono nomi validi, al contrario di myelement che non lo è.
Ciò ci assicura l’assenza di conflitti tra i nostri elementi HTML personalizzati e quelli built-in.
Esempio: “time-formatted”
Per esempio, esiste già l’elemento <time> nell’HTML, per la data/ora. Solo non compie alcuna formattazione del dato di per sé.
Creiamo invece un elemento <time-formatted>, che visualizza l’ora in un formato che consideri la lingua:
<script>
class TimeFormatted extends HTMLElement { // (1)
connectedCallback() {
let date = new Date(this.getAttribute('datetime') || Date.now());
this.innerHTML = new Intl.DateTimeFormat("default", {
year: this.getAttribute('year') || undefined,
month: this.getAttribute('month') || undefined,
day: this.getAttribute('day') || undefined,
hour: this.getAttribute('hour') || undefined,
minute: this.getAttribute('minute') || undefined,
second: this.getAttribute('second') || undefined,
timeZoneName: this.getAttribute('time-zone-name') || undefined,
}).format(date);
}
}
customElements.define("time-formatted", TimeFormatted); // (2)
</script>
<!-- (3) -->
<time-formatted datetime="2019-12-01"
year="numeric" month="long" day="numeric"
hour="numeric" minute="numeric" second="numeric"
time-zone-name="short"
></time-formatted>
- La classe contiene solo il metodo
connectedCallback()che il browser chiama appena l’elemento<time-formatted>viene aggiunto alla pagina (o quando il parser HTML lo riconosce). Il metodo usa il formattatore built-in delle date Intl.DateTimeFormat, ben supportato dai browser, per mostrare l’ora formattata.