自定义元素和connectedCallback():在触发函数之前等待父节点可用

问题描述 投票:0回答:3

我正在使用自定义元素,这非常好。 但我遇到了一个问题:

当调用 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() 之前如何确定父节点是可访问的?

谢谢!

javascript dom custom-element
3个回答
3
投票

这是预期的行为:

connectedCallback
opening 标签上触发,其 lightDOM 尚未解析。 (除非 CE.define 在 DOM 解析之后运行)

connectedCallback

not
意味着您的元素已完全解析或未完全解析。 自定义元素没有像所有工具(Lit、Stencil 等)那样具有 parsedCallback
方法
查看所有答案:

    自定义 HTMLElement 的connectedCallback() 中的textContent 为空
  • 连接自定义 html 元素的回调
  • 当所有子自定义元素已连接时如何拥有“connectedCallback”
TL;博士;

延迟渲染方法的解决方法:

connectedCallback(){ setTimeout(this.render); }

这使浏览器有时间解析更多节点(您的 lightDOM 节点)
并在事件循环为空时执行。

注意:这对于大约 500 到 1000 个节点以下的节点来说效果很好。如果 lightDOM 中有(太多)节点,您的情况可能会有所不同。然后,您需要更长的超时时间,或者添加显式检查所有要创建的 lightDOM 的代码。请参阅:

https://github.com/WICG/webcomponents/issues/809


0
投票
connectedCallback

无法访问与其自身相关的其他元素。如果您认为

custom-element
必须能够存在于 DOM 中的 anywhere 而不依赖于另一个元素,那么这种做法是有意义的。因此,如果没有选择父元素,该元素可能无法正常工作。 实现此目的的一种方法是修改

render

方法以采用参数,该参数将动态地将

tracklist
属性设置为自定义元素。然后从 DOM 中选择
my-element
元素并查找
section

然后,每当自定义元素准备就绪时,使用

customElements.whenDefined

 方法将 
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>

如果我不清楚或您有疑问,请告诉我。

祝你有美好的一天!


0
投票
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();
  }
}
© www.soinside.com 2019 - 2024. All rights reserved.