純粋な HTML+JavaScript だけでカスタムタグを作る
カスタムなタグを作成してコンポーネントを作成するフレームワークを使ったことのある人は多いと思う。
と言うかこのサイトで紹介している LWC なんてまんまそれだし…
で、この タグを作るって仕様的にどうなってるん?
て事で調べてみた。
蛇足が多い…!?
でもなんとか成功したのでその作り方をメモする。
タグを作成して宣言する
ここではあくまでタグを宣言して使うことだけを考える。
なので、仕様は最小限で
<echo-tag message="HAHAHA!"></echo-tag>
こんな感じで書いたら、「HAHAHA」と文字列を出力するだけのタグを考える。
まずは、適当に EchoTag.js
ファイルを作成して以下のように書く
class EchoTag extends HTMLElement { // コンストラクタ constructor() { super(); this._innerText = null; } // この変数に宣言された属性は、追加/削除/更新されたときに attributeChangedCallback が呼ばれる static observedAttributes = ["message"]; // 属性値が更新されたら呼び出されるコールバック。 attributeChangedCallback(name, oldValue, newValue) { this._innerText = newValue; this._updateRendering(); } // このタグが親のタグに配置されると呼び出されるコールバック connectedCallback() { this._updateRendering(); } // JavaScript でタグ作成したときの属性パラメータ get message() { return this._innerText; } set message(v) { this.setAttribute("message", v); } // カスタム関数。ココでは Shadow DOM を宣言して、span タグを作って表示するだけ。 _updateRendering() { this.attachShadow({mode: 'open'}); // append child. const spanElement = document.createElement("span"); spanElement.innerHTML = this._innerText; this.shadowRoot.append(spanElement); } } // カスタム要素として、ブラウザに登録する customElements.define("echo-tag", EchoTag);
タグとして利用する
使う側の HTML は index.html
とでもしておく。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <!-- タグ定義を読み込んで --> <script src="./EchoTag.js"></script> </head> <body> <div><span>Example!</span></div> <!-- 使うだけ --> <echo-tag message="Welcome to custom tag!"></echo-tag> </body> </html>
動かしてみる
非常にシンプルで、書くだけ書いたらサーバを建てよう。
自分はめんどくさいので Python 3.11.x で python -m http.server 8000
でサーバを立てた。
その結果はこの通り
因みに、Shadow DOM を使わない場合は、_updateRendering
を次の様に書く。
_updateRendering() { // this.attachShadow({mode: 'open'}); this.innerHTML = null; // append child. const spanElement = document.createElement("span"); spanElement.innerHTML = this._innerText; this.append(spanElement); // this.shadowRoot.append(spanElement); }
結果が若干異なる。
Shadow DOM に関しては明日調査する…