Как удалить шаблон из автономных пользовательских элементов с помощью vanilla js?

У меня есть пользовательский компонент, который просто показывает карту Таро. Перед настраиваемым элементом я определил шаблон.
В подключенном вызове обратного вызова моего wc я прикрепил сам шаблон к теневому корню, а затем удалил его, клонировав его туда же, в теневой корень. Я сделал это по 2 причинам:

  1. Я хочу, чтобы мой компонент wc был автономным модулем; поэтому я хочу определить свой шаблон в том же месте, что и мой пользовательский элемент.
  2. Кажется, это единственный способ отпечатать мой шаблон, чтобы его можно было использовать, не вставляя его в документ владельца.

    var tmpl = `
        <template id="tmpl">
        <h1 class="tarot-title"><slot name="title">NEED TITLE</slot>
        </h1>
        <img src="${this.imageurl}" alt="">
        <p><slot name="subtitle">NEED A SUBTITLE</slot></p>
    </template>`;
    
    
    
    class BdTarot extends HTMLElement {
    
        ...constructor etc...
    
        connectedCallback() {
            this._shadowRoot.innerHTML = tmpl;
            var _tmpl = this._shadowRoot.querySelector('#tmpl');
            this._shadowRoot.appendChild(_tmpl.content.cloneNode(true));
    
        }
    
    }
    
    customElements.define('bd-tarot', BdTarot);
    

Проблема, которую это создало, заключается в том, что каждый компонент карты Таро, который я использую на своей странице, имеет один и тот же шаблон, являющийся дочерним, все с одним и тем же идентификатором. Так как они в Shadowroot, это имеет значение? Зато смешно пахнет...

Моя цель — просто попытаться понять, как все спецификации веб-компонентов сочетаются друг с другом. Мой вопрос в том, есть ли лучший способ сделать это, чтобы сохранить мой код компонента вместе и не ссылаться на документ владельца? Является ли спецификация шаблона в основном несовместимой с пользовательскими элементами, поскольку импорт html не поддерживается большинством поставщиков браузеров?


person rakitin    schedule 07.09.2017    source источник


Ответы (2)


В двух словах: если вы используете литералы шаблонов, то вам не следует использовать элемент <template>.

Вам не нужно дублировать шаблон, чтобы сохранить коды пользовательского элемента и шаблона вместе.

Вы можете просто заключить свой код в самовыполняющуюся функцию, чтобы быть уверенным, что переменная tmpl не будет переопределена.

(function () {

var tmpl = `
    <h1 class="tarot-title"><slot name="title">NEED TITLE</slot></h1>
    <img src="${this.imageurl}" alt="">
    <p><slot name="subtitle">NEED A SUBTITLE</slot></p>`;


class BdTarot extends HTMLElement {
    constructor() {
        super()      
        this.attachShadow( { mode: 'open' } ) 
             .innerHTML = tmpl;
    }
}

customElements.define('bd-tarot', BdTarot);

})()
<bd-tarot>
<span slot="title">Queen</span>
</bd-tarot>

Если вы хотите сохранить локальную копию шаблона, вы можете скопировать ее в переменную экземпляра (this.tmpl).

person Supersharp    schedule 07.09.2017

Хотя я согласен с утверждением @Supersharp о том, что литерал шаблона и шаблон не следует использовать вместе, я думаю, что есть лучший способ управлять HTML-шаблоном компонента, что-то вроде сочетания ваших подходов.

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

const template = document.createElement('template');
template.innerHTML = `
    <h1 class="tarot-title">
        <slot name="title">NEED TITLE</slot>
    </h1>
    <img src="${this.imageurl}" alt="">
    <p>
        <slot name="subtitle">NEED A SUBTITLE</slot>
    </p>
`;

customElements.define('bd-tarot', class extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({ mode: 'open' }) 
            .appendChild(template.content.cloneNode(true));
    }
})();

Я писал по аналогичному вопросу здесь, упоминая также мою собственную библиотеку, объединяющую большую часть приведенного выше шаблона в несколько API.

person GullerYA    schedule 25.12.2019