如何使用 vanilla js 在自包含的自定义元素中剔除模板?

How to stamp out template in self contained custom elements with vanilla js?

我有一个只显示塔罗牌的自定义组件。 在自定义元素之前我定义了一个模板。
在我的 wc 的 connectedCallback 中,我将模板本身附加到 shadowroot,然后通过在 shadowroot 中克隆它来将其删除。我这样做有两个原因:

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

这造成的问题是我在我的页面上使用的每个塔罗牌组件都有相同的模板 child,都具有相同的 ID。既然他们在 shadowroot 中,这有关系吗?虽然闻起来很有趣...

我的目标只是想了解 Web 组件规范是如何组合在一起的。我的问题是,是否有更好的方法可以将我的组件代码保持在一起并且不引用所有者文档?由于大多数浏览器供应商未采用 html 导入,因此模板规范是否主要与自定义元素不兼容?

简而言之:如果您使用 template literals then you shouldn't use <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) 中。

虽然我同意@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。