嵌套元素(Web组件)无法获取其模板

jam*_*bay 8 javascript web-component shadow-dom html5-template html-imports

我使用带有两个自定义元素(v1)的Web组件做了一个简单的例子,其中一个嵌套在另一个元素中.index.html的:

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Example</title>
  <meta name="description" content="">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="import" href="app-container.html">
</head>
<body>
  <app-container></app-container>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)

APP-container.html:

<link rel="import" href="toolbar.html">
<template id="app-container">
  <app-toolbar></app-toolbar>
</template>
<script>
  customElements.define('app-container', class extends HTMLElement {
    constructor() {
      super();
      let shadowRoot = this.attachShadow({ mode: 'open' });
      const content = document.currentScript.ownerDocument.querySelector('#app-container').content;
      shadowRoot.appendChild(content.cloneNode(true));
    }
  });
</script>
Run Code Online (Sandbox Code Playgroud)

toolbar.html:

<template id="app-toolbar">
  <p>Ok!</p>
</template>
<script>
  customElements.define('app-toolbar', class extends HTMLElement {
    constructor() {
      super();
      let shadowRoot = this.attachShadow({ mode: 'open' });
      const content = document.currentScript.ownerDocument.querySelector('#app-toolbar').content;
      shadowRoot.appendChild(content.cloneNode(true));
    }
  });
</script>
Run Code Online (Sandbox Code Playgroud)

但是在toolbar.html document.currentScript中与app-container.html相同,因此querySelector('#app-toolbar')无法找到带有id的模板app-toolbar.如何解决这个问题呢?

在Chrome 55(不含polyfill)上测试的示例.

Sup*_*arp 18

document.currentScript包含对当前正在解析和执行的脚本的引用.因此,在constructor()调用函数时(从另一个脚本),它不再适用于您的目的 .

相反,你应该在脚本开头的变量中保存它的值,并在构造函数中使用这个变量:

<script>
    var currentScript = document.currentScript
    customElements.define( ... )
    ...
</script>
Run Code Online (Sandbox Code Playgroud)

如果您有多个脚本,则应使用不同的名称.

或者,您可以将ephemeral值封装在闭包中:

(function(owner) {
    customElements.define('app-container', class extends HTMLElement {
        constructor() {
           super();
           let shadowRoot = this.attachShadow({ mode: 'open' });
           const content = owner.querySelector('#app-container').content;
           shadowRoot.appendChild(content.cloneNode(true));
        }
    });
})(document.currentScript.ownerDocument);
Run Code Online (Sandbox Code Playgroud)

这里将值document.currentScript.ownerDocument赋给owner参数,该参数在constructor()被调用时仍然正确定义.

owner 是本地定义的,因此您可以在其他文档中使用相同的名称.