createElement в пользовательском элементе разбивает шаблон
Я создаю два пользовательских элемента, оба добавляются в index.html по ссылке rel="import". Один - это контейнер со слотами, а другой - что-то, чтобы поместить число в слоты. Оба элемента имеют HTML-файл с шаблоном и ссылку на файл js, который определяет их как пользовательские элементы. Чтобы связать объявление класса пользовательского элемента с шаблоном HTML, который я использую:
class PuzzlePiece extends HTMLElement{
constructor(){
super();
console.dir(document.currentScript);
const t = document.currentScript.ownerDocument.getElementById('piece-puzzle');
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(t.content.cloneNode(true));
}
Этот элемент головоломки и контейнер визуализируются правильно, и все это работает, когда вы вручную помещаете их в index.html light dom
<special-puzzle id="grid">
<puzzle-piece id="hello"></puzzle-piece>
</special-puzzle>
Однако, как только я попробую создать и добавить кусок головоломки, используя JS в index.html:
<script>
const addToGrid = document.createElement("puzzle-piece");
document.getElementById("grid").appendChild(addToGrid);
</script>
Я вижу новый кусочек головоломки в специальном паззле, но он не занимает слот, не рендерится, и в консоли есть ошибка:
Uncaught TypeError: Невозможно прочитать свойство 'content' с нулевым значением в новом PuzzlePiece (puzzle-piece.ts:8) в HTMLDocument.createElement (:3:492) в (index):37
Насколько я могу судить, проблема в том, что при использовании document.createElement браузер получает определение класса, но document.currentScript.ownerDocument отличается от того, когда он просто использует HTML-теги вручную. Я считаю, что из-за этого компонент не может найти свой шаблон. Это мой первый вопрос переполнения стека, поэтому любая обратная связь / помощь будет принята с благодарностью!
1 ответ
Решено благодаря потрясающему @Supersharp и их сообщению о переполнении стека
По сути, чтобы сохранить правильный document.currentScript.ownerDocument, мне нужно объявить его в переменной перед классом, а затем использовать эту переменную в классе.
Старый:
class PuzzlePiece extends HTMLElement{
constructor(){
super();
const t = document.currentScript.ownerDocument.getElementById('piece-puzzle');
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(t.content.cloneNode(true));}
Новое:
var importedDoc = document.currentScript.ownerDocument;
class PuzzlePiece extends HTMLElement{
constructor(){
super();
const t = importedDoc.getElementById('piece-puzzle');
const shadowRoot = this.attachShadow({mode: 'open'});
shadowRoot.appendChild(t.content.cloneNode(true));}