簡単なカスタムタグライブラリ

このページで私が作ったカスタムタグライブラリを発表しようと言うのではありません。
属性やプロパティの追加の必要がない、<slot&ft;を備えたレイアウト目的だけのカスタムタグは<template>を書けばよく、JSはごく簡単なもの1つだけで複数のカスタムタグを登録できるのでは、と思ってやってみた実験です。

ソースコード

とりあえずソースコードは次のようになります。
このサンプルは一つのHTMLファイルに書いていますが、カスタムタグ関連部分を差分ファイルに切り出してimportすれば完璧です。

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<title>WebContent Sample</title>

	<-- hoge-tagのテンプレート -->
	<template id="hoge-tag">
		<div class="outer">
			<div><slot></slot></div>
			<div>Hoge</div>
		</div>
		<style>
		.outer {
			border: solid red 1px;
		}
		</style>
	</template>

	<-- fuga-tagのテンプレート -->
	<template id="fuga-tag">
		<div class="outer">
			<div>Fuga</div>
			<div><slot></slot></div>
		</div>
		<style>
		.outer {
			border: solid blue 1px;
		}
		</style>
	</template>

	<-- 全てのカスタムタグを登録するJSの処理 -->
	<script>
	let tmpls = document.getElementsByTagName("template");
	for(let i=0; i<tmpls.length; i++){
		let cls = class extends HTMLElement{
			constructor(){
				super();
			}

			connectedCallback(){
				let sr = this.attachShadow({mode: "open"});
				const tmpl = document.getElementById(tmpls[i].id);
				const clone = document.importNode(tmpl.content, true);
				sr.appendChild(clone);
			}
		};
		customElements.define(tmpls[i].id, cls);
	}
	</script>
</head>
<body>
	<hoge-tag>
		<p>これはほげ</p>
	</hoge-tag>
	<fuga-tag>
		<p>これはふが</p>
	</fuga-tag>
</body>
</html>

説明

テンプレートのルール

ルールは1つだけです。
id属性を登録するタグ名にすることです。
本当は独自データ属性でdata-tagname="登録タグ名"の様にした方が良いと思いますが本質的ではないのでこのサンプルではidを使います。

各テンプレートの内容やスタイルは適当に作ればOKです。
カスタムタグの中に反映したい部分を<slot>で用意しておくだけです。
ただし、ボタンなどのイベント処理が必要な要素を含むカスタムタグはこの単純な仕組みでは構築できません。
単にレイアウト目的のHTMLの機能だけで済むカスタムタグだけが構築できます。

カスタムタグの登録

カスタムタグの登録は次の様になっています。

まず、<template>を全て取得します(35行目)
それをループで処理します。
スープ内ではカスタムタグの匿名クラスを作ります(37〜48行目)。
ポイントは44行目だけです。この匿名クラスはクロージャなので35行目で取得した<template>のリストを参照できます。なのでconst tmpl = document.getElementById(tmpls[i].id)とすることでループ対象の<template>を取得することができ、ループごとにカスタムタグを生成できます。

あとは作ったクラスを即座にcustomElements.define()で登録すれば良いわけです。この時、<template>のidからタグ名を取得します。

もう少し丁寧にやるなら<script>の中身を即時関数でラップすれば何の影響も残らずにすみます。

動作確認

両方のカスタムタグがきちんと機能しています。

これはほげ

これはふが

まとめ

簡単なコードですが相当威力があると思います。
例えば、基本的なページレイアウトのカスタムタグをこの方法で作って、各ページでそれを使うと言う程度でもかなり便利です。

このサイトの場合、

ページ全体

<div>
	<div>ページタイトル領域</div>
	<div>メニュー領域</div>
	<div>本文領域</div>
	<div>フッタ領域</div>
</div>

ページタイトル

<div>
	<div>会社名?</div>
	<div>バナー</div>
</div>

メニュー

<div>
	<ul>
		<li>メニュー1</li>
		<li>メニュー2</li>
		<li>メニュー3</li>
		<li>・・・</li>
	</ul>
</div>

本文のセクション

<div>
	<hn>タイトル</hn>
	<div>本文</div>
</div>

フッタ

<div>
	<ul>
		<li>フッタ左</li>
		<li>フッタ中央</li>
		<li>フッタ右</li>
	</ul>
</div>
と言う部品でできています。

なのでこれらの部品をカスタムタグ化すればレイアウトのために使っている<div>をページのHTMLから見えなくすることができ、カスタムタグを使って見通よく作れるはずです。

こう言う例は多いと思うので非常に威力があると思うわけです。