Nested element (web component) can't get its template

主宰稳场 提交于 2019-12-17 03:18:43

问题


I made a simple example using Web Components with two custom elements (v1) where one is nested in another. 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>

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>

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>

But in the toolbar.html document.currentScript is the same as in the app-container.html and hence querySelector('#app-toolbar') can't find template with id app-toolbar. How to solve this problem?

Example tested on Chrome 55 (without polyfill).


回答1:


document.currentScript contains a reference to the script that is currently parsed and executed. Therefore it is not valid anymore for your purpose when the constructor() function is called (from another script).

Instead you shoud save its value in a variable at the beginning of the script, and use this variable in the constructor:

<script>
    var currentScript = document.currentScript
    customElements.define( ... )
    ...
</script>

If you have multiple scripts, you should use distinct names.

Alternately, you can encapsulate the ephemeral value in a closure:

(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);

Here the value document.currentScript.ownerDocument is assigned to the owner argument which is still defined correctly when constructor() is called.

owner is locally defined so you can use the same name in the other document.



来源:https://stackoverflow.com/questions/41408477/nested-element-web-component-cant-get-its-template

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!