Differenze tra i modi per istanziare dinamicamente un componente web
Esistono diversi modi in cui un componente web (elementi personalizzati autonomi solo per quanto riguarda questa domanda) può "prendere vita".
Ci sono notevoli differenze tra le tre opzioni di seguito?
Opzione 1:
const foo = document.createElement('foo-element');
document.body.appendChild(foo);
Opzione 2:
const div = document.createElement('div');
div.innerHTML = '<foo-element></foo-element>'
const foo = div.firstElementChild;
document.body.appendChild(foo);
Opzione 3:
const foo = new FooElement;
document.body.appendChild(foo);
Ho scritto alcuni test unitari basati su uno stack Karma/Mocha e ho creato le mie istanze con l'opzione 3.
È sufficiente, ciò significa che posso fare affidamento sui componenti con stato/comportamento identico utilizzando entrambi i metodi o è necessario ripetere tutti i miei test con tutte le diverse opzioni di istanziazione applicate?
Uno dei miei componenti Web non viene istanziato utilizzando document.createElementa causa di un errore:
VM977:1 Uncaught DOMException: Failed to construct 'CustomElement': The result must not have attributes at <anonymous>:1:10
Il fatto che lo stesso componente possa essere istanziato senza problemi usando newmi dice che, dietro il sipario, ci devono essere notevoli differenze soprattutto tra new FooElemente document.createElement('foo-element').
Posso scrivere tre test generali per testare tutti e tre i modi di istanziare, di sicuro, ma è sufficiente?
O tutti i miei test esistenti dovrebbero essere eseguiti con tutte e 3 le opzioni di creazione di un'istanza?
O chiesto in modo diverso:
Ogni istanza è esattamente la stessa dopo l'istanziazione? (supponendo che non ci siano errori)
Risposte
La differenza nei 3 metodi si manifesta se ti registri foo-elementcome elemento HTML personalizzato con il CustomElementRegistry.define()metodo. Sulla base della mia sperimentazione, il secondo metodo non può sfruttare alcuna elaborazione speciale fornita registrando l'elemento personalizzato. Inoltre, il primo metodo deve essere eseguito come segue:
document.createElement("p", { is: "foo-element" });
dove ho definito foo-elementper estendere il <p>tag come esempio.
Ad ogni modo, un esempio può spiegarlo meglio. Nel codice sottostante ho definito FooElementdi estendere il <p>tag in modo che venga automaticamente inizializzato con il testo "I am foo".
// Create a class for the element
class FooElement extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
this.innerText = 'I am foo';
}
}
// Define the new element (The CustomElementRegistry is available through the Window.customElements property):
customElements.define('foo-element', FooElement, { extends: 'p' });
Ora esegui il seguente frammento:
window.onload = function() {
class FooElement extends HTMLParagraphElement {
constructor() {
// Always call super first in constructor
super();
this.innerText = 'I am foo';
}
}
customElements.define('foo-element', FooElement, { extends: 'p' });
const div1 = document.createElement('div');
document.body.appendChild(div1);
const foo1 = document.createElement("p", { is: "foo-element" });
div1.appendChild(foo1);
const div2 = document.createElement('div');
document.body.appendChild(div2);
div2.innerHTML = '<foo-element></foo-element>';
const div3 = document.createElement('div');
document.body.appendChild(div3);
const foo3 = new FooElement();
div3.appendChild(foo3);
};
<body>
</body>
Abbiamo creato tutti e tre gli elementi ma solo la sete e la terza opzione hanno effetto per quanto riguarda il raggiungimento della lavorazione speciale desiderata. Se dovessi ispezionare il testo, vedresti che gli effettivi elementi che lo racchiudono sono in realtà <p>tag.
Per quanto ti DOMExceptionriguarda, i primi due metodi che hai mostrato non dovrebbero causare un'eccezione se hai registrato il tuo elemento o meno. Tuttavia, il terzo metodo genererà un'eccezione se FooElementnon è un nodo legittimo come quello creato dall'estensione HTMLParagraphElementcome nell'esempio precedente. Quindi, avrei bisogno di maggiori informazioni sulle circostanze esatte della tua eccezione.
Aggiornare
Qui la classe FooElementnon eredita da un elemento standard e viene generata un'eccezione:
window.onload = function() {
class FooElement {
constructor() {
}
}
const div3 = document.createElement('div');
document.body.appendChild(div3);
const foo3 = new FooElement();
div3.appendChild(foo3);
};
<body>
</body>