追記: npmに公開しました。
追記: webcomponents.orgに公開しました
受け取ったマークアップを1つの塊としてDOMに吐きたい。
DOMParser
を使うと新しいドキュメントの中のbody
要素内に並べられるので1つずつ取り出す必要があります。text/xml
としてパースするとトップレベルの要素が複数あればパースエラーになってしまう( ˘ω˘ )
React.Fragment
のような動きを、JavaScriptだけで実装したい、と思い立ち✍
DEMO: https://codepen.io/heppokofrontend/pen/mdOKJNy
class HTMLDocumentFragmentElement extends HTMLElement {
/** @see https://html.spec.whatwg.org/multipage/custom-elements.html#custom-element-reactions */
connectedCallback() {
const fragment = document.createDocumentFragment();
const childNodes = [...this.childNodes];
for (const node of childNodes) {
fragment.append(node);
}
this.replaceWith(fragment);
}
}
customElements.define('document-fragment', HTMLDocumentFragmentElement);
ドキュメントに吐き出されたとき、この要素の中に入っているノードをフラグメントにすべて収納して自身と入れ替える、という動きをします。
connectedCallback
メソッドはlife-cycle-callbacksです。
ドキュメントに要素が登場したときに呼ばれます。
そのタイミングで、自身(document-fragment cutom element)の子ノードをすべてフラグメントに格納して自信と入れ替えます。
childNodes
は動的オブジェクトであるため、スプレッド演算子を使ってズレないようにします。
ヒント:for...of文がずれる!?NodeListやHTMLCollectionなどの動的オブジェクトを使うときに知っておかなければならないこと
How to use
customElements.define
を読んだ後に次のような活用方法が考えられます。
直接HTMLに書いてみる
<document-fragment>
<p>テキストテキスト</p>
<p>テキストテキスト</p>
</document-fragment>
↓ ページロード後
<p>テキストテキスト</p>
<p>テキストテキスト</p>
JSで出力してみる
const src = `
<p>
Btn clicked!
</p>
<p>
Btn clicked!
</p>
`;
const documentFragmentElement = document.createElement('document-fragment');
documentFragmentElement.innerHTML = src;
document.body.append(documentFragmentElement);
↓ body要素の中身(document-fragment要素はいなくなる)
<p>
Btn clicked!
</p>
<p>
Btn clicked!
</p>
最後に
わざわざカスタム要素を使わないで、素直にfor...of
を使って丁寧に出力するようにすればいいだけと言えばそうなんだけれども、ほかに何かいい方法があれば教えてほしいです!( ˘ω˘ )