【问题标题】:Differences between ways to dynamically instantiate a web component动态实例化 Web 组件的方法之间的差异
【发布时间】:2020-12-14 03:18:20
【问题描述】:

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 FooElementdocument.createElement('foo-element') 之间。

当然,我可以编写三个通用测试来测试所有三种实例化方式,但这是否足够?

或者我所有现有的测试都应该使用所有 3 个实例化选项来运行吗?

或者换个方式问:

每个实例实例化后是否完全相同? (假设没有错误)

【问题讨论】:

    标签: javascript web-component custom-element native-web-component


    【解决方案1】:

    如果您使用CustomElementRegistry.define() 方法将foo-element 注册为自定义HTML 元素,这3 种方法的区别就会显现出来。根据我的实验,第二种方法不能利用注册自定义元素提供的任何特殊处理。另外,第一种方法必须如下:

    document.createElement("p", { is: "foo-element" });
    

    以我定义foo-element 来扩展&lt;p&gt; 标记为例。

    无论如何,一个例子可以更好地解释这一点。在下面的代码中,我定义了FooElement 以扩展&lt;p&gt; 标记以自动使用文本“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' });
    

    现在执行以下sn-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 和第三个选项对实现所需的特殊处理有任何影响。如果您要检查文本,您会发现实际的封闭元素实际上是 &lt;p&gt; 标记。

    就您的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>

    【讨论】:

    • 在您的示例中,显然div2.innerHTML = '&lt;foo-element&gt;&lt;/foo-element&gt;'; 没有意义,因为您的代码扩展了HTMLParagraphElement。如果有的话,它必须是div2.innerHTML = '&lt;p is="foo-element"&gt;&lt;/p&gt;';。另外,我看不出您的&lt;p is="foo-element"&gt; 示例对这里有什么帮助。该项目仅使用自主自定义元素。你诚实的回答不是答案;你触及主题,就是这样。仍然感谢你的尝试。
    • 您的问题是“以下三个选项之间是否存在显着差异?”我给出了一个很长的答案,但“妙语”就在我的答案的第一行:“如果您使用 CustomElementRegistry.define() 方法将 foo-element 注册为自定义 HTML 元素,这 3 种方法的区别就会显现出来。 "我继续证明了这种差异是什么。当然,你的元素是自主元素,所以你可以随意忽略展览。但也许还有其他人在读这个。对不起,这对你没有用。 (更多...)
    • 但是,我确实提到如果您不从实际元素继承,那么选项 3 应该会失败(对我来说确实如此)。查看新的 sn-p。
    • 新的 sn-p 显然不能工作,因为FooElement 没有扩展HTMLElement。此外,它从未注册为自定义元素。
    • 仅供记录(和未来的读者),我没有选择这个答案,它真的不值得赏金或投票。 Stackoverflow 决定为这个回复提供赏金。它根本没有回答这个问题。不幸的是,从表面上看,人们投票赞成可能从未编写过单个自定义元素。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-02
    • 2011-03-15
    • 1970-01-01
    • 2020-11-04
    • 1970-01-01
    • 2011-01-26
    相关资源
    最近更新 更多