为什么我必须推迟 customElement 定义?

Why do I have to defer customElement definitions?

看来我必须在 HTML 主体被解析后才定义自定义元素。如果我之前定义了,自定义元素的内容是空的

这是一个 MWE:

<!DOCTYPE html>
<html lang="en">
<head>
  <script>
    customElements.define('test-one',
      class extends HTMLElement {
        constructor() {
          super()
          console.log(this.textContent)
        }
      }
    )
  </script>
</head>

<body>
  <test-one>First.</test-one>
  <test-two>Another.</test-two>

  <script>
    customElements.define('test-two',
      class extends HTMLElement {
        constructor() {
          super()
          console.log(this.textContent)
        }
      }
    )
  </script>
</body>
</html>

test-one在控制台输出""test-two输出"Another.".

然而,这似乎完全不符合直觉,我浪费了很多时间阅读规范,但我没有找到对这种行为的解释。有任何想法吗?在哪里指定或记录?这不是 Chrome 问题,Firefox 的行为相同。

实际上,您 可以 在将自定义元素添加到 DOM 之前定义它。

您不能做的是访问其 constructor() 中的内容(属性、子树、属性),因为这些元素尚未被解析(正如@Patrick Evans 所建议的)。

在您的示例中,您可以稍等片刻才能访问 textContent 属性。

constructor() {
  super()
  setTimeout( () => console.log(this.textContent) )
}

如果您还想将自定义元素定义放在页眉中,可以等待页面加载。

window.onload => customElements.define(...)

或者,取决于您在等什么:

document.addEventListener( 'DOMContentLoaded', customElements.define(...) )

它在规范中不是黑白分明的,因为它是解析过程的结果,但您可以阅读此 HTML Standard section:

The element's attributes and children must not be inspected, as in the non-upgrade case none will be present, and relying on upgrades makes the element less usable.

"non-upgrade case"是元素在解析之前定义的时候。