Вложенный элемент (веб-компонент) не может получить свой шаблон

Я сделал простой пример, используя веб-компоненты с двумя пользовательскими элементами (v1), где один вложен в другой. 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>

Приложение-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>

Но в toolbar.html document.currentScript такой же, как в app-container.html и, следовательно, querySelector('#app-toolbar') не могу найти шаблон с идентификатором app-toolbar, Как решить эту проблему?

Пример проверен на Chrome 55 (без полизаполнения).

1 ответ

Решение

document.currentScript содержит ссылку на скрипт, который в данный момент анализируется и выполняется. Поэтому это больше не действует для ваших целей, когда constructor() функция вызывается (из другого скрипта).

Вместо этого вы должны сохранить его значение в переменной в начале скрипта и использовать эту переменную в конструкторе:

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

Если у вас есть несколько сценариев, вы должны использовать разные имена.

Кроме того, вы можете инкапсулировать эфемерное значение в замыкании:

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

Здесь значение document.currentScript.ownerDocument назначен на owner аргумент, который все еще определен правильно, когда constructor() называется.

owner определяется локально, поэтому вы можете использовать то же имя в другом документе.

Другие вопросы по тегам