1. はじめに
Web Components を使ってカスタム要素を作成し、そのタグを記述する際に、独自の属性を利用する方法について説明します。
例えば、あるカスタム要素を<my-element>
というタグとして利用する場合に、foobar
という属性を指定したいのであれば、以下のように書けます。
<my-element foobar="10"></my-element>
カスタム要素を実装するためのクラス定義において、プロパティとして実装することが合理的である値があった場合に、先程のような「HTMLタグの属性」をそのオブジェクトのプロパティとして透過的に利用するこができれば、処理の実装がラクになります(*1)。また、HTMLタグにあらかじめ属性値を指定しておくことで、プロパティの初期値として利用することができます。
本記事では、Web Components のカスタム要素において、属性値をプロパティとして利用する方法について説明します。
(*1)this.getAttribute(属性名)
の代わりにthis.属性名
で値を参照できたり、this.setAttribute(属性名, 値)
の代わりに、this.属性名 = 値
と値を代入できてラクです。しかも、属性値は文字列しか使えませんが、プロパティはいろいろな型の値が使えます。
2. カスタム属性の使い方
基本的なコード例
ここでは、カスタム要素で rate
という属性を使うコードの例を紹介します。属性値は文字列型しかとれないのですが、rate
という属性は整数として利用したいので、何箇所かで型変換を行っていることにも注意してください。
最終的に、以下のようなHTMLタグを記述すると想定します。
<my-element rate="1">Default</my-element>
カスタム要素のクラス定義をモジュールとして使えるように、my-element.js
という名前のファイルに以下を記述します。コメントに各コードの説明を書いておきました。
export default class extends HTMLElement {
constructor() {
super();
// 省略
}
/* カスタム要素が DOM に追加されたときに実行されます。 */
connectedCallback() {
// getter が定義されているので、this.rate で値が参照できます(getterが実行されます)。
if (!Number.isInteger(this.rate)) {
// setter が定義されているので、「this.rate = 値」で値をセットできます
this.rate = 1; // setter が実行されます
}
}
/* Getter */
get rate() {
// 属性値を取得し、整数に変換して返します
return parseInt(this.getAttribute('rate'));
}
/* Setter */
set rate(value) {
// 渡された値を属性値として保持します
// ここで数値をセットしても属性値は文字列になります(自動変換)
this.setAttribute('rate', value);
}
// 省略
};
- 「get 属性名()」でプロパティの Getter を定義しています。
- 「set 属性名(値)」でプロパティの Setter を定義しています。
- 実際には
connectedCallback()
の後半やその他のメソッド内で、this.rate
を使った処理があるはずという想定です。
HTMLファイルには以下を記述します。
<!-- 目的の位置にカスタム要素のタグを記述します -->
<my-elm rate="1">Default</my-elm>
<script type="module">
// カスタムクラスをインポートします
import MyElement from './my-element.js';
// カスタムクラスにタグ名をつけます
customElements.define('my-element', MyElement);
</script>
attributeChangedCallback()
を使う場合
特定の属性値が「追加」「削除」「変更」された時に発火する attributeChangedCallback()
というメソッドも使えます。
そのためには、まずクラス定義の中で、observedAttributes()
メソッドを実装します。
static get observedAttributes() {
return ['rate'];
}
戻り値となる配列には、監視対象にするプロパティ名をセットします。
そして、attributeChangedCallback()
メソッドを実装します。
/*
* @param {string} name - 属性名
* @param {string} oldValue - 元の値
* @param {string} newValue - 新しい値
*/
attributeChangedCallback(name, oldValue, newValue) {
// 何かしらプロパティに関する処理
console.log(name, oldValue, newValue);
}
このメソッドでは、引数として渡された属性値に付随するその他の属性値をセット・変更するのに使われることが多いようです。例えば、引数で渡された属性値に合った tabindex
属性や Web Accessibility Initiative (WAI) の属性などをセットします。カスタム要素 v1: 再利用可能なウェブ コンポーネント | Web | Google Developers にもその例が載っています。
値がいらない属性 (disabledなど)の場合
HTMLタグの属性には値がいらないものがあります。例えば、disabled
です。
<my-elm disabled>Default</my-elm>
カスタム要素 v1: 再利用可能なウェブ コンポーネント | Web | Google Developers には、この手の属性をプロパティとして利用する場合のコードが載っています。そこに載っているdisabled
属性の Getter / Setter が以下です。
カスタム要素 v1: 再利用可能なウェブ コンポーネント から抜粋 (※ コメントはこちらで追加)
/*
* disabled の Getter
* @returns {boolean}
*/
get disabled() {
// True/False を返すため hasAttribute() を使っています
return this.hasAttribute('disabled');
}
/*
* disabled の Setter
*/
set disabled(val) {
if (val) {
// disabled属性に値は必要ないので、'' をセットしています
this.setAttribute('disabled', '');
} else {
// 「disabled が False である」とは、
// disabled 属性自体の記述がないことになるので、
// disabled 属性を削除しています
this.removeAttribute('disabled');
}
}
コメントにも説明を書きましたが、「HTMLタグの disabled
属性の記述」と「HTMLElement のプロパティとしての扱い (Boolean)」の差異を Getter / Setter で上手く変換しています。
3. おわりに
Web Components のカスタム要素を作成する場合、「独自の属性を追加して利用する」というのは割と頻繁に行うことになると思います。まだこのあたりについて参考になる文献も少ないので、本記事にまとめてみました。