# [Web Components](https://developer.mozilla.org/docs/Web/Web_Components) を実装した ```js customElements.define("my-element", class extends HTMLElement { constructor() { super(); this.attachShadow({mode: "open"}); } attributeChangedCallback() { this.#_attributeChangedCallback(); } connectedCallback() { this.#_connectedCallback(); } }); ``` ## [Custom elements](https://developer.mozilla.org/docs/Web/Web_Components/Using_custom_elements) ### [`CustomElementRegistry.define`](https://developer.mozilla.org/docs/Web/API/CustomElementRegistry/define) 新しい要素が登録できます。 ここでは `my-element` 要素を登録しています。([要素名には多少の制限があるようです](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name)) ### [The lifecycle callbacks](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_custom_elements#using_the_lifecycle_callbacks) 要素のライフサイクルに応じて起動できます。 ```js #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](https://developer.mozilla.org/docs/Web/API/Document_Object_Model) に追加されるたびに実行されます。 ここでは最初に追加されたときに [`MutationObserver.observe`](https://developer.mozilla.org/docs/Web/API/MutationObserver/observe) を呼び出しています。要素が変更されたときにコールバック関数 `this.#_init` を呼び出します。 また*最初*に [`Node.childNodes`](https://developer.mozilla.org/docs/Web/API/Node/childNodes) 等を使いたいときは `constructor` よりも `connectedCallback` で使うようにしています。`constructor` ではエラーを吐くことがあったので。 ## [Shadow DOM](https://developer.mozilla.org/docs/Web/Web_Components/Using_shadow_DOM) ```js 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`](https://developer.mozilla.org/docs/Web/API/Element/attachShadow) Shadow DOM が追加できます。[`Element.shadowRoot`][Element.shadowRoot] への参照を返します。 ### [`Element.shadowRoot`][Element.shadowRoot] [Element.shadowRoot]: https://developer.mozilla.org/docs/Web/API/Element/shadowRoot [`ShadowRoot`](https://developer.mozilla.org/docs/Web/API/ShadowRoot) オブジェクトです。 ここでは [Shadow DOM にスタイルシートを追加しています](https://developer.mozilla.org/en-US/docs/Web/Web_Components/Using_shadow_DOM#styling_the_shadow_dom)。 Shadow DOM は(基本的に)外のスタイリングに影響しない、されないようです。 - [継承](https://developer.mozilla.org/docs/Web/CSS/inheritance)はするようです - [CSS custom properties](https://developer.mozilla.org/docs/Web/CSS/Using_CSS_custom_properties)も継承するようです #### [`:host`](https://developer.mozilla.org/docs/Web/CSS/:host) 擬似クラス Shadow host が選択できます。 ここでは `my-element` 要素のスタイルに `display: block` を加えています。 #### [`::part`](https://developer.mozilla.org/docs/Web/CSS/::part) 擬似要素 Shadow tree の内の要素が選択できます。