Any way to keep a custom elemnt's template markup and style outside of a javascript string?

倖福魔咒の 提交于 2021-01-28 00:07:47

问题


This is an example of the use of custom elements from developers.google.com:

let tmpl = document.createElement('template');
tmpl.innerHTML = `
  <style>:host { ... }</style> <!-- look ma, scoped styles -->
  <b>I'm in shadow dom!</b>
  <slot></slot>
`;

customElements.define('x-foo-shadowdom', class extends HTMLElement {
  constructor() {
    super(); // always call super() first in the constructor.

    // Attach a shadow root to the element.
    let shadowRoot = this.attachShadow({mode: 'open'});
    shadowRoot.appendChild(tmpl.content.cloneNode(true));
  }
  ...
});

While this works I find this approach oddly ugly. HTML and CSS should reside in .html and .css files, not as Javascript strings.

At the same time I don’t know how to move this content to .html or .css files?

Well yes I could populate the main HTML file, namely index.html, with <template> tags for all custom elements that may be ever used – but doesn't this defeat the purpose of custom elements?

<link rel="import"> could be promising but it’s been dropped.

Any other options?

(Or am I incorrect to find the original solution ugly?)


回答1:


You could use fetch() to get an HTML file for your Custom Element content.

customElements.define('x-foo-shadowdom', class extends HTMLElement {
    constructor() {
        super()
        this.attachShadow( {mode: 'open'} )
    }

    async connectedCallback() {
        let res = await fetch( 'x-foo.html' )
        this.shadowRoot.innerHTML = await res.text()
    }
}

NB: because fetch() and text() are asynchronous, you must add async before connectedCallback() and await before the method calls.

You can also get separate CSS content simply by using <link> in the HTML code.


am I incorrect to find the original solution ugly?

Yes it's ugly. If you want to use a template literal then no need to put it in a <template> element and clone it.

Instead, use the template literal directly:

shadowRoot.innerHTML =  `
  <style>:host { ... }</style> <!-- look ma, scoped styles -->
  <b>I'm in shadow dom!</b>
  <slot></slot>
`;

Note that there's an advantage with template literals vs separate HTML: you can use insert variables easily. Example with an incremental clic counter:

customElements.define( 'click-counter', class extends HTMLElement {
  connectedCallback() {
    let count = 0
    let sh = this.attachShadow( { mode: 'open' } )    
    this.onclick = () => sh.innerHTML = `<button>${count++}</button>`
    this.click() 
  }
} )
<click-counter></click-counter>


来源:https://stackoverflow.com/questions/56992820/any-way-to-keep-a-custom-elemnts-template-markup-and-style-outside-of-a-javascr

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