在 connectedCallback 中等待元素升级:FireFox 和 Chromium 的区别
wait for Element Upgrade in connectedCallback: FireFox and Chromium differences
2021 年 3 月更新:
修复了 FireFox 错误,现在与 Chromium 和 Safari 的行为相同。
这意味着在connectedCallback
中等待JS EventLoop为空(用setTimeout
或requestAnimationFrame
)现在是一个跨浏览器的方法
connectedCallback(){
setTimeout(()=>{
// can access lightDOM here
}); // ,0 not required
}
事件循环到底是什么? - 菲利普·罗伯茨
https://www.youtube.com/watch?v=8aGhZQkoFbQ
2020 年 10 月 28 日更新:
现被 Mozilla 工程师 Anne van Kesteren 报告为 FireFox 中的一个错误:
FireFox 调用 connectedCallback 太晚了:
https://bugzilla.mozilla.org/show_bug.cgi?id=1673811
第一个post五月。 2020 年:
在使用 FireFox 一周后,再次被这个 Chrome 元素升级问题困扰。
在交付给 Chromium 浏览器之前忘记将代码包装在 setTimeout 中。
FireFox 打印:ABCD
Chromium 打印:ADCD
问题:为什么不一样?
<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>
历年相关回答:
How to have a 'connectedCallback' for when all child custom elements have been connected
How to wait for Custom Element reference to be "upgraded"?
更新 #1
- Apple/Safari:打印:ADCD(与 Chromium 相同)
注意:Chromium Blink 引擎是 Apples (WebKit)WebCore 代码的一个分支!!
更新 #2
通过 Supersharps 参考,我们找到了相关主题:
(2016) 文档解析器创建自定义元素时的 connectedCallback 计时
https://github.com/w3c/webcomponents/issues/551
(2019) 子项更改或解析器完成解析子项时需要回调
https://github.com/w3c/webcomponents/issues/809
FireFox 与 Chromium 中的回调顺序:
来源:https://jsfiddle.net/CustomElementsExamples/n20bwckt/
我认为 Chrome/Safari 行为对于初学者来说不太直观,但对于一些更复杂的场景(例如子自定义元素),它会更加一致。
请参阅下面的不同示例。他们在 Firefox 中的行为很奇怪...
另一个我没有勇气编码的用例:当解析文档时,可能你还没有结束文档。因此,创建自定义元素时,在获得结束标记(永远不会到达)之前,您无法确定是否获得了所有子元素。
根据 Ryosuke Niwa 对于 WebKit 的说法:
The problem then is that the element won't get connectedCallback until
all children are parsed. For example, if the entire document was a
single custom element, that custom element would never receive
connectedCallback until the entire document is fetched & parsed even
though the element is really in the document. That would be bad.
所以最好不要等到创建后立即连接自定义元素,这意味着没有子元素。
<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) 方式调整规范:
Fixes w3c/webcomponents#551 by ensuring that
insertions into the DOM trigger connectedCallback immediately, instead
of putting the callback reaction on the the backup element queue and
letting it get triggered at the next microtask checkpoint. This means
connectedCallback will generally be invoked when the element has zero
children, as expected, instead of a random number depending on when the
next custom element is seen.
我们可以得出结论,Firefox 也遵循规范...是的,但由于上述原因,我们不应依赖 connectedCallback
中的内容。
2021 年 3 月更新:
修复了 FireFox 错误,现在与 Chromium 和 Safari 的行为相同。
这意味着在connectedCallback
中等待JS EventLoop为空(用setTimeout
或requestAnimationFrame
)现在是一个跨浏览器的方法
connectedCallback(){
setTimeout(()=>{
// can access lightDOM here
}); // ,0 not required
}
事件循环到底是什么? - 菲利普·罗伯茨
https://www.youtube.com/watch?v=8aGhZQkoFbQ
2020 年 10 月 28 日更新:
现被 Mozilla 工程师 Anne van Kesteren 报告为 FireFox 中的一个错误:
FireFox 调用 connectedCallback 太晚了:
https://bugzilla.mozilla.org/show_bug.cgi?id=1673811
第一个post五月。 2020 年:
在使用 FireFox 一周后,再次被这个 Chrome 元素升级问题困扰。
在交付给 Chromium 浏览器之前忘记将代码包装在 setTimeout 中。
FireFox 打印:ABCD
Chromium 打印:ADCD
问题:为什么不一样?
<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>
历年相关回答:
How to have a 'connectedCallback' for when all child custom elements have been connected
How to wait for Custom Element reference to be "upgraded"?
更新 #1
- Apple/Safari:打印:ADCD(与 Chromium 相同)
注意:Chromium Blink 引擎是 Apples (WebKit)WebCore 代码的一个分支!!
更新 #2
通过 Supersharps 参考,我们找到了相关主题:
(2016) 文档解析器创建自定义元素时的 connectedCallback 计时
https://github.com/w3c/webcomponents/issues/551(2019) 子项更改或解析器完成解析子项时需要回调
https://github.com/w3c/webcomponents/issues/809
FireFox 与 Chromium 中的回调顺序:
来源:https://jsfiddle.net/CustomElementsExamples/n20bwckt/
我认为 Chrome/Safari 行为对于初学者来说不太直观,但对于一些更复杂的场景(例如子自定义元素),它会更加一致。
请参阅下面的不同示例。他们在 Firefox 中的行为很奇怪...
另一个我没有勇气编码的用例:当解析文档时,可能你还没有结束文档。因此,创建自定义元素时,在获得结束标记(永远不会到达)之前,您无法确定是否获得了所有子元素。
根据 Ryosuke Niwa 对于 WebKit 的说法:
The problem then is that the element won't get connectedCallback until all children are parsed. For example, if the entire document was a single custom element, that custom element would never receive connectedCallback until the entire document is fetched & parsed even though the element is really in the document. That would be bad.
所以最好不要等到创建后立即连接自定义元素,这意味着没有子元素。
<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) 方式调整规范:
Fixes w3c/webcomponents#551 by ensuring that insertions into the DOM trigger connectedCallback immediately, instead of putting the callback reaction on the the backup element queue and letting it get triggered at the next microtask checkpoint. This means connectedCallback will generally be invoked when the element has zero children, as expected, instead of a random number depending on when the next custom element is seen.
我们可以得出结论,Firefox 也遵循规范...是的,但由于上述原因,我们不应依赖 connectedCallback
中的内容。