Web 组件(仅针对此问题的自治自定义元素)可以通过多种方式“栩栩如生”。
以下三个选项之间是否存在显着差异?
选项1:
const foo = document.createElement('foo-element');
document.body.appendChild(foo);
选项 2:const div = document.createElement('div');
div.innerHTML = '<foo-element></foo-element>'
const foo = div.firstElementChild;
document.body.appendChild(foo);
选项 3:const foo = new FooElement;
document.body.appendChild(foo);
我基于 Karma/Mocha 堆栈编写了一些单元测试,并使用选项 3 创建了我的实例。这是否足够,也就是说,我可以使用任何一种方法来依赖具有相同状态/行为的组件吗 ,或者是否有必要重复我所有的测试并应用所有不同的实例化选项?
我的一个 Web 组件无法使用
document.createElement
实例化因为一个错误:VM977:1 Uncaught DOMException: Failed to construct 'CustomElement': The result must not have attributes at <anonymous>:1:10
使用
new
可以毫无问题地实例化相同的组件这一事实告诉我,幕后肯定有显着差异,尤其是在 new FooElement
之间。和 document.createElement('foo-element')
.当然,我可以编写三个通用测试来测试所有三种实例化方式,但这是否足够?
还是应该使用所有 3 个实例化选项来运行我所有现有的测试?
或者换个方式问:
每个实例实例化后是否完全相同? (假设没有错误)
最佳答案
注册foo-element
就可以看出3种方式的区别。作为带有 CustomElementRegistry.define()
的自定义 HTML 元素方法。根据我的实验,第二种方法不能利用注册自定义元素提供的任何特殊处理。此外,第一种方法必须按如下方式完成:
document.createElement("p", { is: "foo-element" });
我在哪里定义了foo-element
延长 <p>
以标签为例。无论如何,一个例子可以更好地解释这一点。在下面的代码中,我定义了
FooElement
延长 <p>
使用文本“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' });
现在执行以下代码段: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>
我们创建了所有三个元素但只有 thirst 和第三种选项才能达到所需的特殊处理效果。如果您要检查文本,您会发现实际的封闭元素实际上是
<p>
标签。至于您的
DOMException
关心的是,无论您是否注册了元素,您显示的前两个方法都不应导致异常。但是,如果 FooElement
第三种方法会抛出异常。不是合法节点,例如通过扩展 HTMLParagraphElement
创建的如上例所示。因此,我需要有关您的异常的确切情况的更多信息。更新
这里上课
FooElement
不继承自标准元素并引发异常:window.onload = function() {
class FooElement {
constructor() {
}
}
const div3 = document.createElement('div');
document.body.appendChild(div3);
const foo3 = new FooElement();
div3.appendChild(foo3);
};
<body>
</body>
关于javascript - 动态实例化 Web 组件的方法之间的差异,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63578724/