[base.js]
const initCustomElement = async (template) => {
const res = await fetch(template)
const html = await res.text()
const doc = new DOMParser().parseFromString(html, "text/html")
const fragment = document.createDocumentFragment()
fragment.append(...doc.head.childNodes, ...doc.body.childNodes)
return fragment
}
export class Base extends HTMLElement {
constructor() {
super()
const C = this.constructor
if (!C.ready) {
C.ready = initCustomElement(C.template)
}
this.attachShadow({ mode: "open" })
C.ready.then((fragment) => {
this.shadowRoot.append(fragment.cloneNode(true))
})
}
}
[foo-bar.js]
import { Base } from "./base.js"
customElements.define("foo-bar", class extends Base {
static template = "foo-bar.html"
})
[foo-bar.html]
<style>
.foo { font-size: 20px; }
.bar { color: red; }
</style>
<div>
<div class="foo">FOO</div>
<div class="bar">BAR</div>
</div>
innerHTML やスタイルは別の HTML ファイルに書く
script タグは HTML に含めず import される JavaScript ファイル側に書いてる
CustomElement の constructor の処理で HTML を fetch して ShadowDOM に append
表示するためのページ
[page.html]
<script type="module" src="foo-bar.js"></script>
<foo-bar></foo-bar>