【问题标题】:Understanding customElements processing order了解 customElements 处理顺序
【发布时间】:2020-03-28 19:45:57
【问题描述】:

在某个时间点,父自定义元素可以访问其子元素,然后才能使用自定义方法。

class CustomParent extends HTMLElement {
  connectedCallback() {
    // works
    this.children[0].textContent = "bar";

    // works
    setTimeout(() => this.children[0].test(), 0);

    // throws a Type error
    this.children[0].test();
  }
}

customElements.define("custom-parent", CustomParent);


class CustomChild extends HTMLElement {
  test() {
    this.textContent = "baz";
  }
}

customElements.define("custom-child", CustomChild);

document.body.innerHTML = `
<custom-parent>
  <custom-child>foo</custom-child>  
</custom-parent>
`;

这怎么可能?推迟this.children[0].test()是否安全?

【问题讨论】:

    标签: javascript custom-element


    【解决方案1】:

    这是由于自定义元素的upgrading process

    第一步:当你执行document.body.innerHTML = '&lt;custom-parent&gt;&lt;custom-child&gt;foo&lt;/custom-child&gt;&lt;/custom-parent&gt;'时,这2个元素作为未知元素插入到页面中。

    第二步:首先升级父元素。它可以作为 unknown 元素访问其子元素(然后更新其textContent 属性)。但它无法访问访问自定义元素test() 方法...因为它还不是自定义元素!

    第三步:子元素升级之后立即得到test()方法。

    第四步:延迟的test() 调用在逻辑上有效:-)

    请参见下面的示例。它使用querySelectorAll( ':not(:defined)' ) 表示子级在其父级之后升级。

    class CustomParent extends HTMLElement {
      constructor() { super() ; console.log( 'parent upgraded') }
      connectedCallback() {
        console.log( 'parent connected', this.children[0].outerHTML )
        // works
        this.children[0].textContent = 'bar'    
        // works
        setTimeout( () => this.children[0].test() )
        // throws a Type error
        try { 
           this.children[0].test() 
        } catch ( e ) { 
          //this shows the parent is upgraded, but not its child 
          var not_upgraded = document.querySelectorAll( ':not(:defined)' )
          console.log( 'not upgraded: ', ...not_upgraded )    
        }    
      }
    }
    
    customElements.define( 'custom-parent', CustomParent )
    
    class CustomChild extends HTMLElement {
      constructor() { super() ; console.log( 'child upgraded') }      
      test() { this.textContent = 'baz' }
    }
    
    customElements.define( 'custom-child', CustomChild ) 
    
    document.body.innerHTML = `
      <custom-parent>
        <custom-child>foo</custom-child>  
      </custom-parent>`

    【讨论】:

    • 这很有帮助。我对customElements.define 方法感到困惑。我想象在其调用之后创建的每个 custom-child 元素都将是“已知的”,它们的所有逻辑都附加在它们上面。我还意识到customElements.upgrade 相当于调用构造函数。如果我在你的 try 块之前写customElements.upgrade(this),每个孩子都会同步升级,如果我在构造函数中调用它,我会得到一个递归函数。现在我想知道是像我一样推迟行动还是在行动之前升级孩子(会不会有副作用?)。
    • 其实这和你创建元素的方式有关(这里是innerHTML)。或者,如果您使用 new 创建元素,然后将它们插入 appendChild,则在将其插入文档时,您将已经拥有添加的方法。只要您了解它的工作原理,我认为没有一种方法比另一种更好。
    • @geoffrey 谢谢我现在不存在upgrade() 方法:-)
    猜你喜欢
    • 1970-01-01
    • 2017-06-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-04
    • 1970-01-01
    • 1970-01-01
    • 2023-03-31
    相关资源
    最近更新 更多