我正在使用自定义元素,这非常好。 但我遇到了一个问题:
当调用 connectedCallback() 函数时,该节点似乎尚未到达其在 DOM 中的位置,因此我无法访问其父级 - 而我需要它们。
class myElement extends HTMLElement{
constructor() {
super();
this.tracklist = undefined;
}
connectedCallback(){
this.render();
}
render(){
this.tracklist = this.closest('section');
// following code requires this.tracklist!
// ...
}
window.customElements.define('my-element', myElement);
在调用 render() 之前如何确定父节点是可访问的?
谢谢!
这是预期的行为:
connectedCallback
在 opening 标签上触发,其 lightDOM 尚未解析。 (除非 CE.define 在 DOM 解析之后运行)
connectedCallback
not意味着您的元素已完全解析或未完全解析。 自定义元素没有像所有工具(Lit、Stencil 等)那样具有
parsedCallback
延迟渲染方法的解决方法:
connectedCallback(){
setTimeout(this.render);
}
这使浏览器有时间解析更多节点(您的 lightDOM 节点) 并在事件循环为空时执行。
注意:这对于大约 500 到 1000 个节点以下的节点来说效果很好。如果 lightDOM 中有(太多)节点,您的情况可能会有所不同。然后,您需要更长的超时时间,或者添加显式检查所有要创建的 lightDOM 的代码。请参阅:
https://github.com/WICG/webcomponents/issues/809connectedCallback
无法访问与其自身相关的其他元素。如果您认为
custom-element必须能够存在于 DOM 中的 anywhere 而不依赖于另一个元素,那么这种做法是有意义的。因此,如果没有选择父元素,该元素可能无法正常工作。 实现此目的的一种方法是修改
render
方法以采用参数,该参数将动态地将
tracklist
属性设置为自定义元素。然后从 DOM 中选择 my-element
元素并查找 section
。然后,每当自定义元素准备就绪时,使用
方法将
section
和 my-element
连接在一起。此方法返回一个 Promise,每当定义自定义元素时都会解析该 Promise,并让您能够执行回调。参见下面的示例:
// Do something whenever the element is ready.
window.addEventListener('load', function() {
// Wait for the document to load so the DOM has been parsed.
window.customElements.whenDefined('my-element').then(() => {
const myElement = document.querySelector('my-element');
// Only do something if the element exists on the page.
if (myElement !== null) {
const tracklist = myElement.closest('section');
myElement.render(tracklist);
console.log(myElement.tracklist);
}
});
});
// Create element.
class myElement extends HTMLElement{
constructor() {
super();
this.tracklist = null;
}
render(tracklist){
this.tracklist = tracklist;
// following code requires this.tracklist!
// ...
}
}
// Define element.
window.customElements.define('my-element', myElement);
<section>
<my-element></my-element>
</section>
如果我不清楚或您有疑问,请告诉我。
祝你有美好的一天!
Promise
可能有用:
// DomReady.js
class DomReady extends HTMLElement {
constructor() {
super();
this.domReadyPromise = new Promise(resolve => (this.domReadyResolve = resolve));
}
connectedCallback() {
this.domReadyResolve();
}
domReady() { return this.domReadyPromise; }
}
// ParentCustom.js
class ParentCustom extends DomReady {
connectedCallback() {
super.connectedCallback();
...
}
}
// ChildCustom.js
class ChildCustom extends HTMLElement {
async connectedCallback() {
await document.querySelector('parent-custom').domReady();
}
}