では、Webコンポーネントについて学び、独自のカスタムHTMLタグを作成することに興味がありますか? この投稿では、 CustomElementsとShadowDOMを使って手を出すための基本的な構文と概念について説明します。
ばかげたものを作りますスタイル付きのタイトルを単純にスタンプするカスタム要素。 あまり有用ではありませんが、いくつかの開始概念を示すのに役立ちます。
入門
最初に、カスタム要素に関するすべて(スタイルルール、マークアップ、ES6クラス定義)を含む別のJavaScriptファイルを作成し、最後にカスタム要素を登録します。 カスタム要素を使用するHTMLファイルでは、そのJavaScriptファイルを含めるだけで、ページで新しいタグの使用を開始できます。
すべてをIIFEでラップして、適切な測定を行いましょう。
(function() {
// the good stuff goes here
})();
次に、HTMLElementを拡張するカスタム要素のクラスを定義しましょう。
(function() {
class MyTitle extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<style>
h1 {
font-size: 2.5rem;
color: hotpink;
font-family: monospace;
text-align: center;
text-decoration: pink solid underline;
text-decoration-skip: ink;
}
</style>
<h1>Hello Alligator!</h1>
`;
}
}
window.customElements.define('my-title', MyTitle);
})();
注意すべき点がいくつかあります。
- ES6クラス内では、thisは要素インスタンス自体を参照します。
- 要素がDOMに追加されると、connectedCallbackメソッドがトリガーされます。 イベントハンドラーなどのクリーンアップに役立つ要素をDOMから削除すると呼び出される、disconnectedCallbackメソッドもあります。
- カスタム要素をcustomElement.defineに登録(定義)し、タグ名を最初の引数として渡し、次に要素を定義するクラスを2番目の引数として渡します。 要素を定義することで、HTMLドキュメントで要素を使用できるようになります。 タグ名は、ハイフンで区切って少なくとも2語にする必要があることに注意してください。 これは、将来のHTML要素がカスタム要素と衝突するのを防ぐためです。
このような単純なカスタム要素を使用すると、 customElements.define の呼び出しで、クラスを匿名クラスとして直接定義することもできます。
(function() {
window.customElements.define(
'my-title',
class extends HTMLElement {
connectedCallback() {
this.innerHTML = `
<style>
h1 {
font-size: 2.5rem;
color: hotpink;
font-family: monospace;
text-align: center;
text-decoration: pink solid underline;
text-decoration-skip: ink;
}
</style>
<h1>Hello Alligator!</h1>
`;
}
}
);
})();
すべてがJavaScriptに含まれており、スタンドアロンのHTMLマークアップがないことに気付くでしょう。 これは、おそらく残念ながら、 HTMLインポートが水中で死んでいるように見えるためです。Webコンポーネントの今後の道は、ES6文字列リテラルを使用してJavaScriptでマークアップとスタイルを定義することです。
ShadowDOM
上記の例はすべてうまくいっていますが、大きな問題が1つあります。それは、スタイルがカスタム要素にスコープされていないことです。 つまり、ページ上のすべての h1 タグは、下線付きのホットピンクになります。 このコンポーネントのスタイルがその外界に影響を与えないようにするためのアドホックな解決策は、マークアップをdivのようなものの中にラップしてから、ラッパーのみをターゲットとするセレクターでスタイルを適用することです。
this.innerHTML = `
<style>
.wrap-my-title h1 {
font-size: 2.5rem;
color: hotpink;
font-family: monospace;
text-align: center;
text-decoration: pink solid underline;
text-decoration-skip: ink;
}
</style>
<div class="wrap-my-tile">
<h1>Hello Alligator!</h1>
</div>
`;
マークアップのどこかにwrap-my-titleを持つ別の要素がある場合、それは素晴らしいことではなく、絶対確実ではありません。 さらに、 h1 のような単純なCSSセレクターを使用できれば、パフォーマンスが向上し、はるかに優れたものになります。 これがShadowDOM[X28X]の出番です。 Shadow DOMを使用すると、スタイルをカスタム要素にスコープして、ブリードアウトしないようにすることができます。
Shadow DOMを使用するには、 shadow root を要素にアタッチしてから、シャドウルート内の要素のマークアップを定義します。
(function() {
class MyTitle extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
h1 {
font-size: 2.5rem;
color: hotpink;
font-family: monospace;
text-align: center;
text-decoration: pink solid underline;
text-decoration-skip: ink;
}
</style>
<h1>Hello Alligator!</h1>
`;
}
}
window.customElements.define('my-title', MyTitle);
})();
注意すべき点がいくつかあります。
- クラスコンストラクターは、シャドウルートをアタッチし、その内部htmlを定義するのに適した場所です。
- カスタム要素のクラスにコンストラクターがある場合は、常に super()を呼び出す必要があります。
- シャドウルートのモードは、openまたはclosedのいずれかです。 おそらくopenのみを使用することになります。そうしないと、innerHTMLを設定できなくなるためです。
Shadow DOMを使用すると、ブラウザのコンソールでマークアップがどのように表示されるかを次に示します。
代替構文
template 要素を作成し、その innerHTML を設定してから、テンプレートのコンテンツを新しい子としてシャドウルートに複製することでも同じ結果を得ることができます。
(function() {
const template = document.createElement('template');
template.innerHTML = `
<style>
h1 {
font-size: 2.5rem;
color: hotpink;
font-family: monospace;
text-align: center;
text-decoration: pink solid underline;
text-decoration-skip: ink;
}
</style>
<h1>Hello Alligator!</h1>
`;
class MyTitle extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
this.shadowRoot.appendChild(template.content.cloneNode(true));
}
}
window.customElements.define('my-title', MyTitle);
})();
使用法
カスタム要素の使用は、スクリプトファイルをページに追加してから、他の通常のHTML要素と同じように要素を使用するのと同じくらい簡単です。 ただし、カスタム要素には常に終了タグが必要であることに注意してください。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="./my-counter.js"></script>
</head>
<body>
<my-title></my-title>
</body>
</html>
私たちの要素は完全に本番環境に対応しているわけではないことに注意してください。 現在のように、この要素はいくつかの最新のブラウザでのみ機能します。 ES6クラスや文字列リテラルなどの全面的にサポートされていないJavaScript機能用のBabelのようなトランスパイラーを介してコードを実行し、カスタム要素とシャドウDOMにポリフィルを使用する必要があります。 別の投稿で、Webコンポーネントのポリフィルの使用について説明します。