Web Components API JavaScript
Nei moderni browser è disponibile una nuova API CustomElementRegistry che permette di creare degli elementi HTML custom.
In pratica, similmente a come avviene in React creando un componente, è possibile fare una cosa simile nativamente nel browser (ovviamente escluso Internet Explorer che ormai è superato).
Nel costruttore della classe:
Il tutto si traduce con questo codice JavaScript
A questo punto abbiamo un nuovo elemento HTML che possiamo riusare anche più volte nella stessa pagina con attributi diversi (vedi esempio a inizio pagina)
In pratica, similmente a come avviene in React creando un componente, è possibile fare una cosa simile nativamente nel browser (ovviamente escluso Internet Explorer che ormai è superato).
Ricarica la pagina per far ripartire il countdown.
Implementazione
Ad esempio è possibile creare un nuovo elemento HTML sgart-countdown che visualizza il decremento di un numero preimpostato (attributo start-count) ogni secondoHTML
<sgart-countdown start-count="12"></sgart-countdown>
<script type="text/javascript" src="sgart-web-components.js"></script>
Attenzione il nome del nuovo elemento HTML deve contenere il segno meno - questo per evitare conflitti con i nomi dei tag standard presenti e futuri.
L'implementazione del codice associato lo si fa con i seguenti passi:- si crea una nuova classe (class) che eredita da HTMLElement
- si associa il nome del nuovo elemento alla classe, con customElements.define(nome, classe)
Nel costruttore della classe:
- va richiamato, come prima cosa, il metodo super() (obbligatorio)
- si crea un elemento shadow con this.attachShadow({ mode: 'open' });
- si aggiungono gli elementi HTML necessari (wrapper) e gli eventuali stili CSS (style)
- sia aggancia (attach) gli elementi e gli stili all'elemento shadow (this.shadowRoot.append(style, wrapper)
- se necessario si implementano gli eventi (lifecycle callbacks)
Il tutto si traduce con questo codice JavaScript
JavaScript: sgart-web-components.js
// Autonomous custom elements
class SgartCountdown extends HTMLElement {
constructor() {
// Always call super first in constructor
super();
// Create a shadow root (open = can access via JavaScript in main page with Element.shadowRoot)
this.attachShadow({ mode: 'open' }); // sets and returns 'this.shadowRoot'
// Element functionality written in here
const wrapper = document.createElement('span');
wrapper.setAttribute('class', 'wrapper');
// Create some CSS to apply to the shadow dom
const style = document.createElement('style');
style.textContent = `
.wrapper {
display: inline-block;
width: 100px;
text-align: center;
border: 1px solid red;
}
.end {
background-color: #800;
}`;
// attach the created elements to the shadow DOM
this.shadowRoot.append(style, wrapper);
this._wrapper = wrapper;
this.readProperty();
this.start();
}
readProperty() {
this._count = parseInt(this.getAttribute('start-count'));
if (isNaN(this._count) || this._count < 1) {
this._count = 0;
}
}
start() {
this.update();
this._timer = setInterval(() => {
if (this._count > 0)
this._count--;
this.update(this._count);
}, 1000);
}
update() {
this._wrapper.innerHTML = this._count;
if (this._count <= 0) {
if (this._timer !== null)
clearInterval(this._timer);
this._wrapper.classList.add('end');
}
}
/*
* lifecycle callbacks
*/
// invoked each time the custom element is appended into a document-connected element. This will happen each time the node is moved, and may happen before the element's contents have been fully parsed.
connectedCallback() {
console.log('SgartCountdown added to page.');
this.shadowRoot.addEventListener('click', e => {
console.log('event', e);
});
}
// invoked each time the custom element is disconnected from the document's DOM.
disconnectedCallback() {
console.log('SgartCountdown removed from page.');
}
// Invoked each time the custom element is moved to a new document.
adoptedCallback() {
console.log('SgartCountdown moved to new page.');
}
// per gestire una proprietà con attributeChangedCallback devo primo osservarla (observe) con un motodo statico
static get observedAttributes() { return ['start-count']; }
// Invoked each time one of the custom element's attributes is added, removed, or changed. Which attributes to notice change for is specified in a static get observedAttributes method
attributeChangedCallback(name, oldValue, newValue) {
console.log('SgartCountdown attributes changed.', name, oldValue, newValue);
}
}
// defines a new custom element
customElements.define('sgart-countdown', SgartCountdown);
A questo punto abbiamo un nuovo elemento HTML che possiamo riusare anche più volte nella stessa pagina con attributi diversi (vedi esempio a inizio pagina)
HTML
<sgart-countdown start-count="12"></sgart-countdown>
<sgart-countdown start-count="24"></sgart-countdown>
<sgart-countdown start-count="7"></sgart-countdown>
<sgart-countdown start-count="0"></sgart-countdown>
<script type="text/javascript" src="sgart-web-components.js"></script>