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

MiB*_*MiB 2 javascript web-component custom-element

似乎我必须在解析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>
Run Code Online (Sandbox Code Playgroud)

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

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

Sup*_*arp 5

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

你不能做的是访问它的内容(属性,子树,属性)constructor(),因为这些元素尚未被解析(正如@Patrick Evans建议的那样).

在您的示例中,您可以等待一段时间访问该textContent属性.

constructor() {
  super()
  setTimeout( () => console.log(this.textContent) )
}
Run Code Online (Sandbox Code Playgroud)

如果您仍想将自定义元素定义放在标题中,则可以等待加载页面.

window.onload => customElements.define(...)
Run Code Online (Sandbox Code Playgroud)

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

document.addEventListener( 'DOMContentLoaded', customElements.define(...) )
Run Code Online (Sandbox Code Playgroud)

它在规范中不是黑白分明的,因为它是解析过程的结果,但是你可以阅读这个HTML标准部分:

不得检查元素的属性和子元素,因为在非升级的情况下不会出现任何属性和子元素,并且依赖于升级会使元素变得不可用.

"非升级案例"是在解析元素之前定义元素的时间.

  • 请注意,如果您想要一种方法来检测内容何时被解析而不是依赖于`setTimeout`,您可以使用[MutationObserver](https://developer.mozilla.org/en-US/docs/Web/API/MutationObserver )观察`childList`更改并在它被解雇后断开连接,[jsfiddle demo here](http://jsfiddle.net/m5f6wo2p/).可能会增加一点开销,但它比setTimeout更可靠. (2认同)