首页 > 解决方案 > 在 connectedCallback 中等待 Element Upgrade:FireFox 和 Chromium 的区别

问题描述

2021 年 3 月更新:

修复了 FireFox 错误,现在的行为与 Chromium 和 Safari 相同。

这意味着等待 JS EventLoop 为空(使用setTimeoutor requestAnimationFrameconnectedCallback现在是一种跨浏览器方法

connectedCallback(){
 setTimeout(()=>{
   // can access lightDOM here
 }); // ,0 not required
}

事件循环到底是什么?- 菲利普·罗伯茨
https://www.youtube.com/watch?v=8aGhZQkoFbQ



2020 年 10 月 28 日更新:



五月第一次发帖。2020:

在使用 FireFox 一周后,再次被这个 Chrome Element 升级问题所困扰。

在交付给 Chromium 浏览器之前忘记将代码包装在 setTimeout 中。

问题:为什么不同?

<script>
  customElements.define('my-element', class extends HTMLElement {
    connectedCallback() {
      console.log(this.innerHTML);// "A" in FireFox, "" in other Browsers
      if (this.innerHTML == "A")
        this.innerHTML = this.innerHTML + "B";
      else
        setTimeout(() => this.innerHTML = this.innerHTML + "D");
    }
  })
</script>

<my-element>A</my-element><my-element>C</my-element>

过去几年的相关答案:

更新#1

注意:Chromium Blink 引擎是 Apples (WebKit)WebCore代码的一个分支!!

更新#2

通过 Supersharps 参考我们找到了相关的线程:

FireFox 与 Chromium 中的回调顺序:

来源:https ://jsfiddle.net/CustomElementsExamples/n20bwckt/

标签: callbackweb-componentclass-methodcustom-element

解决方案


我认为 Chrome/Safari 的行为对初学者来说不太直观,但是对于一些更复杂的场景(例如使用子自定义元素),它会更加一致。

请参阅下面的不同示例。他们在 Firefox 中的行为很奇怪......

另一个我没有勇气编码的用例:当一个文档被解析时,可能你还没有文档的结尾。因此,当一个自定义元素被创建时,你不能确定你得到了它的所有子元素,直到你得到结束标签(它永远不会到达)。

根据 WebKit 的 Ryosuke Niwa 所说:

然后的问题是,在所有子元素都被解析之前,该元素不会得到 connectedCallback 。例如,如果整个文档是单个自定义元素,则该自定义元素将永远不会收到 connectedCallback,直到整个文档被获取和解析,即使该元素确实在文档中。那会很糟糕。

所以最好不要等待并在创建自定义元素后立即连接它,这意味着没有子元素。

<script>
    customElements.define( 'c-e', class extends HTMLElement {} ) 
    customElements.define('my-element', class extends HTMLElement {
      connectedCallback() {
        console.log(this.innerHTML, this.childNodes.length)
        let span = document.createElement( 'span' )
        if (this.innerHTML.indexOf( 'A' ) >= 0 )
            span.textContent = 'B'
        else
            span.textContent = 'D'
        setTimeout( () => this.appendChild( span ) )
      }
    })
</script>
<my-element>A</my-element><my-element>C</my-element>
<br>
<my-element><c-e></c-e>A</my-element><my-element>A<c-e></c-e></my-element>
<br>
<my-element><c-e2></c-e2>A</my-element><my-element>A<c-e2></c-e2></my-element>

据我了解,对此达成共识,导致以(Chrome/Safari)方式调整规范:

修复w3c/webcomponents#551,确保插入 DOM 立即触发 connectedCallback,而不是将回调反应放在备份元素队列上并让它在下一个微任务检查点触发。这意味着 connectedCallback 通常会在元素有零个子元素时调用,正如预期的那样,而不是一个随机数,具体取决于何时看到下一个自定义元素。

connectedCallback我们可以得出结论,Firefox 也遵循规范......是的,但由于上述原因,我们不应该依赖其中的内容。


推荐阅读