Différences entre les méthodes d'instanciation dynamique d'un composant Web
Un composant Web (éléments personnalisés autonomes uniquement en ce qui concerne cette question) peut "prendre vie" de plusieurs manières.
Y a-t-il des différences notables entre les trois options ci-dessous?
Option 1:
const foo = document.createElement('foo-element');
document.body.appendChild(foo);
Option 2:
const div = document.createElement('div');
div.innerHTML = '<foo-element></foo-element>'
const foo = div.firstElementChild;
document.body.appendChild(foo);
Option 3:
const foo = new FooElement;
document.body.appendChild(foo);
J'ai écrit des tests unitaires basés sur une pile Karma / Mocha et créé mes instances avec l'option 3.
Est-ce suffisant, c'est-à-dire, puis-je compter sur les composants ayant un état / comportement identique en utilisant l'une ou l' autre méthode , ou est-il nécessaire de répéter tous mes tests avec toutes les différentes options d'instanciation appliquées?
L'un de mes composants Web ne parvient pas à être instancié à l'aide document.createElementd'une erreur:
VM977:1 Uncaught DOMException: Failed to construct 'CustomElement': The result must not have attributes at <anonymous>:1:10
Le fait que le même composant puisse être instancié sans problème en utilisant newme dit que, derrière le rideau, il doit y avoir des différences notables notamment entre new FooElementet document.createElement('foo-element').
Je peux bien sûr écrire trois tests généraux pour tester les trois méthodes d'instanciation, mais est-ce suffisant?
Ou tous mes tests existants devraient-ils être exécutés avec les 3 options d'instanciation?
Ou demandé différemment:
Chaque instance est-elle exactement la même après l'instanciation? (en supposant qu'il n'y a pas d'erreur)
Réponses
La différence entre les 3 méthodes se manifeste si vous vous inscrivez en foo-elementtant qu'élément HTML personnalisé avec la CustomElementRegistry.define()méthode. Sur la base de mon expérimentation, la deuxième méthode ne peut tirer parti d'aucun traitement spécial fourni par l'enregistrement de l'élément personnalisé. En outre, la première méthode doit être effectuée comme suit:
document.createElement("p", { is: "foo-element" });
où j'ai défini foo-elementd'étendre la <p>balise à titre d'exemple.
Quoi qu'il en soit, un exemple peut mieux expliquer cela. Dans le code ci-dessous, j'ai défini FooElementd'étendre la <p>balise pour qu'elle soit automatiquement initialisée avec le texte «Je suis 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' });
Exécutez maintenant l'extrait de code suivant:
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>
Nous avons créé les trois éléments, mais seules la soif et la troisième option ont un effet sur la réalisation du traitement spécial souhaité. Si vous deviez inspecter le texte, vous verriez que les éléments inclus sont en fait des <p>balises.
En ce qui vous DOMExceptionconcerne, les deux premières méthodes que vous avez montrées ne devraient pas provoquer d'exception que vous ayez enregistré votre élément ou non. Cependant, la troisième méthode lèvera une exception si ce FooElementn'est pas un nœud légitime tel que créé en s'étendant HTMLParagraphElementcomme dans l'exemple ci-dessus. J'aurais donc besoin de plus d'informations sur les circonstances exactes de votre exception.
Mettre à jour
Ici, la classe FooElementn'hérite pas d'un élément standard et une exception est levée:
window.onload = function() {
class FooElement {
constructor() {
}
}
const div3 = document.createElement('div');
document.body.appendChild(div3);
const foo3 = new FooElement();
div3.appendChild(foo3);
};
<body>
</body>