Web Components を実装しました。Custom elements と Shadow DOM を使いました。

更新 公開)

Web Components を実装した

customElements.define("my-element", class extends HTMLElement {
    constructor() {
        super();
        this.attachShadow({mode: "open"});
    }
    attributeChangedCallback() {
        this.#_attributeChangedCallback();
    }
    connectedCallback() {
        this.#_connectedCallback();
    }
});

Custom elements

CustomElementRegistry.define

新しい要素が登録できます。

ここではmy-element要素を登録しています。(要素名には多少の制限があるようです

The lifecycle callbacks

要素のライフサイクルに応じて起動できます。

#attr;
#attr_old;
static get observedAttributes() {
    return ["my-attr"];
}
attributeChangedCallback(name, oldValue, newValue) {
    if ("my-attr" !== name) {
        return;
    }
    this.#attr = newValue;
    this.#attr_old = oldValue;
}

#connected = false;
connectedCallback() {
    if (this.#connected) {
        return;
    }
    this.#_init();
    (new MutationObserver(this.#_init)).observe(this, this.#_options);
    this.#connected = true;
}

attributeChangedCallback

observedAttributesで指定した属性が追加、削除、変更されるたびに実行されます。

ここではmy-attr属性を指定しています。古い値oldValueと新しい値newValueをそれぞれ#attr_oldプロパティと#attrプロパティに設定します。

connectedCallback

要素がDOMに追加されるたびに実行されます。

ここでは最初に追加されたときにMutationObserver.observeを呼び出しています。要素が変更されたときにコールバック関数this.#_initを呼び出します。

また最初Node.childNodes等を使いたいときはconstructorよりもconnectedCallbackで使うようにしています。constructorではエラーを吐くことがあったので。

Shadow DOM

this.attachShadow({mode: "open"}).appendChild(document.createElement("style")).textContent = `:host {
    display: block;
}`;

const style = document.createElement("link");
style.rel = "stylesheet";
style.href = "style.css";
this.shadowRoot.appendChild(style);

Element.attachShadow

Shadow DOM が追加できます。Element.shadowRootへの参照を返します。

Element.shadowRoot

ShadowRootオブジェクトです。

ここでは Shadow DOM にスタイルシートを追加しています

Shadow DOM は(基本的に)外のスタイリングに影響しない、されないようです。

:host擬似クラス

Shadow host が選択できます。

ここではmy-element要素のスタイルに display: block を加えています。

::part擬似要素

Shadow tree の内の要素が選択できます。