加载 Web 组件时的事件

Event when web component has loaded

我有一个这样的网络组件

<template id="component">
    <link href="/static/css/main.cacbacc7.css" rel="stylesheet">
    <script src="/static/js/vendor.js" type="text/javascript"></script>
    <script src="/static/js/bundle.js" type="text/javascript"></script>
    <span id="react-app"></span>
</template>

<script>
  (function (window, document) {
    const doc = (document._currentScript || document.currentScript).ownerDocument;
    const proto = Object.create(HTMLElement.prototype, {
      attachedCallback: {
        value: function () {
          const template = doc.querySelector('template#component').content;
          const shadowRoot = this.attachShadow({ mode: 'open' });
          shadowRoot.appendChild(template.cloneNode(true));
          // executeThis() when all scripts have been loaded
        }
      },
    });
    document.registerElement('react-webcomponent', { prototype: proto });
  })(window, document);
</script>

我可以知道我 template 中的所有 script 标签何时加载了吗?

更新

我目前正在做的是

const scripts = [...shadowRoot.querySelectorAll('script')];
let scriptsLoaded = 0;
scripts.forEach(function (script) {
  script.addEventListener('load', function () {
    if (++scriptsLoaded >= scripts.length) {
      LoadReactAppIntoShadowDomContainer(shadowRoot.querySelector('#react-app'));
    }
  })
});

但我希望有更好的方法。

关于可能的重复项:它适用于 Web 组件吗?

据我了解,截至目前,

  • 您的影子根

  • 中的 dom 的 onload 没有事件侦听器
  • 当你定义一个自定义元素时,你可以有一个 connectedCallback 当你将一个元素附加到你的 DOM

    [=52= 时调用它]

根据您的尝试,在我看来,您正在尝试确定影子 DOM 加载其内部脚本的确切时间

据我所知,脚本不局限于您的元素,而是全局的。

所以与其尝试做你现在正在做的事情,不如

  • 正在查询影子根的 DOM 结构,收集脚本标签并附加一个 onload,

您可以简单地将一个 onload 加载到标签上,它们像往常一样工作。

此外,如果您想要观察阴影 DOM 的变化,您可能会对 mutation observers 感兴趣,一旦它达到 attached 及以后。

据我所知,在构建元素本身/附加元素之前,您无法观察到 DOM 变化

或者,如果您在不同的文件中定义元素并且更喜欢使用 HTML Imports 将它们导入到文档中,

您可以使用导入文档中的 webcomponentsready 侦听器,它会在所有 DOM 被导入、解析和加载时触发

如果确实有办法观察DOM或者听模板附件到你的元素,我也想知道。

此外,由于您正在尝试将 React 应用程序嵌入到自定义元素中,这可能就是为什么您有知道何时调用 loadreactapp 函数的问题,您可能需要考虑使用 slots 在你的影子 DOM 中,它打开了你的元素在浏览器上注册后可以分发内容的地方

只需通过传入属性 slot=<slotname>

添加您的应用程序或其他自定义元素

你的更新示例是我所知道的最好的方法。

我有一个类似的问题,希望在通过标签导入 CSS 的组件上阻止 FOUC。

我能找到的唯一解决方案是根据您的更新。 QS ShadowRoot 找到 <link><scripts>,为每个添加一个加载事件侦听器并比较加载计数。

您可能会考虑的一种优化是,当计数匹配时,您可以从影子根本身调度您自己的自定义加载事件,您的组件影子根(或树的更上层)上的侦听器可以处理。

var event = new CustomEvent('load');
shadowRoot.dispatchEvent(event);

如果你想让它冒泡并穿过阴影边界,你需要将 composed : true 添加到事件参数中。

var event = new CustomEvent('load', {bubbles : true, composed : true});
shadowRoot.dispatchEvent(event);