问题
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