ã«ã¹ã¿ã è¦ç´ ã®ä½¿ç¨
ã¦ã§ãã³ã³ãã¼ãã³ãã®ä¸»ãªç¹å¾´ã®ã²ã¨ã¤ã¯ãã«ã¹ã¿ã è¦ç´ ã使ã§ãããã¨ã§ããã¤ã¾ããã¦ã§ãéçºè ã«ãã£ã¦åä½ãå®ç¾©ããããã©ã¦ã¶ã¼ã§å©ç¨å¯è½ãªè¦ç´ ã»ãããæ¡å¼µãã HTML è¦ç´ ã§ãã
ãã®è¨äºã§ã¯ãã«ã¹ã¿ã è¦ç´ ã«ã¤ãã¦ç´¹ä»ããããã¤ãã®ä¾ã説æãã¾ãã
ã«ã¹ã¿ã è¦ç´ ã®ç¨®é¡
ã«ã¹ã¿ã è¦ç´ ã«ã¯ 2 ã¤ã®ç¨®é¡ãããã¾ãã
-
èªå¾åã«ã¹ã¿ã è¦ç´ (Autonomous custom element) 㯠HTML è¦ç´ ã®åºåºã¯ã©ã¹ã§ãã
HTMLElementãç¶æ¿ãã¾ãã 1 ããåä½ãå®è£ ããå¿ è¦ãããã¾ãã -
ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ (Customized built-in element) ã¯ãæ¨æº HTML è¦ç´ ãä¾ãã°
HTMLImageElementãHTMLParagraphElementãç¶æ¿ãã¾ãããããã®å®è£ ã«ãããæ¨æºè¦ç´ ã®ç¹å®ã®ã¤ã³ã¹ã¿ã³ã¹ã®åä½ãæ¡å¼µããã¾ããã¡ã¢: Safari ã¯ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã«å¯¾å¿ããè¨ç»ãããã¾ããã詳ããã¯
is屿§ã®ãªãã¡ã¬ã³ã¹ãåç §ãã¦ãã ããã
ã©ã¡ãã®ç¨®é¡ã®ã«ã¹ã¿ã è¦ç´ ã«ã¤ãã¦ãã使ãã¦ä½¿ç¨ããããã®åºæ¬çãªæ®µéã¯åãã§ãã
- æåã«åä½ã®å®è£ ãã JavaScript ã¯ã©ã¹ãå®ç¾©ãããã¨ã§è¡ãã¾ãã
- ããããç¾å¨ã®ãã¼ã¸ã«ã«ã¹ã¿ã è¦ç´ ã®ç»é²ãè¡ãã¾ãã
- æå¾ã«ãèªåã® HTML ã¾ã㯠JavaScript ã³ã¼ãå ã§ã«ã¹ã¿ã è¦ç´ ã使ç¨ãã¾ãã
ã«ã¹ã¿ã è¦ç´ ã®å®è£
ã«ã¹ã¿ã è¦ç´ ã¯ãHTMLElement ãæ¡å¼µããã¯ã©ã¹ï¼èªå¾åè¦ç´ ã®å ´åï¼ã¾ãã¯ã«ã¹ã¿ãã¤ãºããã¤ã³ã¿ã¼ãã§ã¤ã¹ï¼ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã®å ´åï¼ã¨ãã¦å®è£
ããã¾ãããã®ã¯ã©ã¹ã¯èªåã§å¼ã³åºãã®ã§ã¯ãªãããã©ã¦ã¶ã¼ã«ãã£ã¦å¼ã³åºããã¾ããã¯ã©ã¹ãå®ç¾©ããå¾ãã«ã¹ã¿ã è¦ç´ ãç»é²ããå¿
è¦ãããã¾ããããã«ããã HTML ãã¼ã¯ã¢ããã§è¦ç´ ãè¨è¿°ãããã document.createElement() ãå¼ã³åºããããããªã©ãæ¨æºç㪠DOM ææ³ãç¨ãã¦ãã®ã¤ã³ã¹ã¿ã³ã¹ã使ã§ããããã«ãªãã¾ãã
以ä¸ã¯ãæå°éã®ã«ã¹ã¿ã è¦ç´ ã§ã<p> è¦ç´ ãã«ã¹ã¿ãã¤ãºããå®è£
ä¾ã§ãã
class WordCount extends HTMLParagraphElement {
constructor() {
super();
}
// è¦ç´ ã®æ©è½ãããã«æ¸ã
}
æå°éã®èªå¾åã«ã¹ã¿ã è¦ç´ ã®å®è£ ã¯æ¬¡ã®ã¨ããã§ãã
class PopupInfo extends HTMLElement {
constructor() {
super();
}
// è¦ç´ ã®æ©è½ãããã«æ¸ã
}
ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ãåæç¶æ ãæ¢å®å¤ã®è¨å®ãã¤ãã³ããªã¹ãã¼ã®ç»é²ãã·ã£ãã¦ã«ã¼ãã使ãããã¨ãªã©ãå¯è½ã§ãããã®æç¹ã§ã¯ãè¦ç´ ã®å±æ§ãåè¦ç´ ãæ¤æ»ããããæ°ãã屿§ãåè¦ç´ ã追å ãããããªãã§ãã ãããè¦ä»¶ã®ãã¹ã¦ã«ã¤ãã¦ã¯ãRequirements for custom element constructors and reactions ãåç §ãã¦ãã ããã
ã«ã¹ã¿ã è¦ç´ ã®ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯
ã«ã¹ã¿ã è¦ç´ ãç»é²ãããã¨ããã¼ã¸ã®ã³ã¼ããã«ã¹ã¿ã è¦ç´ ã¨ç¹å®ã®æ¹æ³ã§ããåããè¡ãéã«ããã©ã¦ã¶ã¼ããã®ã¯ã©ã¹ã®ç¹å®ã®ã¡ã½ãããå¼ã³åºãã¾ãã 仿§æ¸ã§ã¯ãããã®ã¡ã½ããã®å®è£ ããã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ãã¨å¼ãã§ãã¾ããããããã®ã¡ã½ãããæä¾ãããã¨ã§ããããã®ã¤ãã³ãã«å¿çãã¦ã³ã¼ããå®è¡ãããã¨ãã§ãã¾ãã
ã«ã¹ã¿ã è¦ç´ ã®ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã«ã¯ã以ä¸ã®ãã®ãå«ã¾ãã¾ãã
connectedCallback(): è¦ç´ ãææ¸ã«è¿½å ããããã³ã«å¼ã³åºããã¾ãã仿§ã§ã¯ãéçºè ã¯å¯è½ãªéããã«ã¹ã¿ã è¦ç´ ã®è¨å®ãã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ãªãããã®ã³ã¼ã«ããã¯ã§å®è£ ãããã¨ãæ¨å¥¨ãã¦ãã¾ããdisconnectedCallback(): è¦ç´ ãææ¸ããåé¤ããããã³ã«å¼ã³åºããã¾ããconnectedMoveCallback(): å®ç¾©ããã¦ããå ´åãããã¯ãconnectedCallback()ããã³disconnectedCallback()ã®ä»£ããã«ãè¦ç´ ãElement.moveBefore()ã«ãã£ã¦ DOM å ã®å¥ã®å ´æã«ç§»åããããã³ã«å¼ã³åºããã¾ãã ããã¯ãè¦ç´ ãå®éã« DOM ã«è¿½å ã¾ãã¯é¤å»ããã¦ããªãå ´åã«ãconnectedCallback()ããã³disconnectedCallback()ã³ã¼ã«ããã¯å ã§åæå/ã¯ãªã¼ã³ã¢ããã³ã¼ããå®è¡ãããã®ãé¿ããããã«ä½¿ç¨ãã¾ãã詳細ã¯ãã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã¨ç¶æ ãä¿æããç§»åãåç §ãã¦ãã ãããadoptedCallback(): è¦ç´ ãæ°ããææ¸ã«ç§»åããããã³ã«å¼ã³åºããã¾ããattributeChangedCallback(): 屿§ã夿´ã追å ãåé¤ãç½®æãããã¨ãã«å¼ã³åºããã¾ãããã®ã³ã¼ã«ããã¯ã®è©³ç´°ã«ã¤ãã¦ã¯ã屿§ã®å¤æ´ã¸ã®å¿çãåç §ãã¦ãã ããã
ãããã®ã©ã¤ããµã¤ã¯ã«ã¤ãã³ããè¨é²ããæå°éã®ã«ã¹ã¿ã è¦ç´ ã¯æ¬¡ã®ã¨ããã§ãã
// è¦ç´ ã®ããã®ã¯ã©ã¹ã使
class MyCustomElement extends HTMLElement {
static observedAttributes = ["color", "size"];
constructor() {
// ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ã常㫠super ãæåã«å¼ã³åºã
super();
}
connectedCallback() {
console.log("ã«ã¹ã¿ã è¦ç´ ããã¼ã¸ã«è¿½å ããã¾ããã");
}
disconnectedCallback() {
console.log("ã«ã¹ã¿ã è¦ç´ ããã¼ã¸ããé¤å»ããã¾ããã");
}
connectedMoveCallback() {
console.log("ã«ã¹ã¿ã è¦ç´ ã moveBefore() ã§ç§»åããã¾ããã");
}
adoptedCallback() {
console.log("ã«ã¹ã¿ã è¦ç´ ãæ°ãããã¼ã¸ã¸ç§»åããã¾ããã");
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(`屿§ ${name} ã夿´ããã¾ããã`);
}
}
customElements.define("my-custom-element", MyCustomElement);
ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã¨ç¶æ ãä¿æããç§»å
ã«ã¹ã¿ã è¦ç´ ã® DOM å ã®ä½ç½®ã¯ãé常㮠HTML è¦ç´ ã¨åæ§ã«ã§ããããã©ã¤ããµã¤ã¯ã«ã«ä¼´ãå¯ä½ç¨ãèæ ®ããªããã°ãªãã¾ããã
ã«ã¹ã¿ã è¦ç´ ãç§»åããããã³ã«ï¼Element.moveBefore() ã Node.insertBefore() ãªã©ã®ã¡ã½ãããä»ãã¦ï¼ãdisconnectedCallback() ããã³ connectedCallback() ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ãããããã®æç¹ã§çºè¡ããã¾ããããã¯ãè¦ç´ ã DOM ããåæããã忥ç¶ãããããã§ãã
ããã¯æå³éãã®åä½ããããã¾ããããã ãããããã®ã³ã¼ã«ããã¯ã¯é常ãè¦ç´ ã®ã©ã¤ããµã¤ã¯ã«ã®å§ã¾ããçµããã«å®è¡ãããå¿ è¦ãªåæåãã¯ãªã¼ã³ã¢ããã³ã¼ããå®è£ ããããã«ä½¿ç¨ããã¾ãããã®ãããè¦ç´ ãç§»åãããæï¼é¤å»ããããæ¿å ¥ããããããæã§ã¯ãªãï¼ã«ããããå®è¡ããã¨ããã®ç¶æ ã«åé¡ãçããå¯è½æ§ãããã¾ããä¾ãã°ãè¦ç´ ãã¾ã å¿ è¦ã¨ãã¦ããä¿åãã¼ã¿ã誤ã£ã¦åé¤ãã¦ãã¾ãå¯è½æ§ãããã¾ãã
è¦ç´ ã®ç¶æ
ãç¶æãããå ´åã¯ãè¦ç´ ã¯ã©ã¹å
ã§ connectedMoveCallback() ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ãå®ç¾©ããã®ãæé©ã§ããããããã Element.moveBefore() ã¡ã½ããã使ç¨ãã¦è¦ç´ ãç§»åãã¾ãï¼Node.insertBefore() ãªã©ã®é¡ä¼¼ã¡ã½ããã®ä»£ããã«ï¼ããã®ãã¨ã¯ã connectedMoveCallback() ã connectedCallback() ããã³ disconnectedCallback() ã®ä»£ããã«å®è¡ããããã¨ã«ãªãã¾ãã
空㮠connectedMoveCallback() ã追å ãã¦ãä»ã® 2 ç¨®é¡ ã®ã³ã¼ã«ããã¯ãå®è¡ãããã®ã忢ããããç¬èªã®ãã¸ãã¯ãè¨è¼ãã¦ç§»åãå¦çãããã¨ãã§ãã¾ãã
class MyComponent {
// ...
connectedMoveCallback() {
console.log("ç¬èªã®ç§»åå¦çã®ãã¸ãã¯ã¯ãã¡ãã");
}
// ...
}
ã«ã¹ã¿ã è¦ç´ ã®ç»é²
ã«ã¹ã¿ã è¦ç´ ããã¼ã¸ã§å©ç¨ã§ããããã«ããã«ã¯ãWindow.customElements ã® define() ã¡ã½ãããå¼ã³åºãã¾ãã
define() ã¡ã½ããã¯ã以ä¸ã®å¼æ°ãåãã¾ãã
name-
è¦ç´ ã®ååãããã¯å°æåã§å§ã¾ãããã¤ãã³ãå«ã¿ã仿§æ¸ã® definition of a valid name ã«è¨è¼ããã¦ãããã®ä»ã®ç¹å®ã®ã«ã¼ã«ãæºããå¿ è¦ãããã¾ãã
constructor-
ã«ã¹ã¿ã è¦ç´ ã®ã³ã³ã¹ãã©ã¯ã¿ã¼é¢æ°ã
options-
ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã®ã¿ã«å«ã¾ããããã¯åä¸ã®ããããã£
extendsãå«ããªãã¸ã§ã¯ãã§ããããã¯ãæ¡å¼µããçµã¿è¾¼ã¿è¦ç´ ã®ååãæå®ããæååã§ãã
ä¾ãã°ããã®ã³ã¼ãã¯ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã§ãã WordCount ãç»é²ãã¾ãã
customElements.define("word-count", WordCount, { extends: "p" });
ãã®ã³ã¼ãã¯ãPopupInfo ã¨ããèªå¾åã«ã¹ã¿ã è¦ç´ ãç»é²ãã¾ãã
customElements.define("popup-info", PopupInfo);
ã«ã¹ã¿ã è¦ç´ ã®ä½¿ç¨
ã«ã¹ã¿ã è¦ç´ ãå®ç¾©ãç»é²ããã¨ãã³ã¼ãã§ä½¿ç¨ã§ããããã«ãªãã¾ãã
ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã使ç¨ããã«ã¯ãçµã¿è¾¼ã¿è¦ç´ ã使ç¨ãã¾ãããã«ã¹ã¿ã åã is 屿§ã®å¤ã¨ãã¦ä½¿ç¨ãã¾ãã
<p is="word-count"></p>
èªå¾åã«ã¹ã¿ã è¦ç´ ãç¬èªã«ä½æãã¦ä½¿ç¨ããã«ã¯ãçµã¿è¾¼ã¿ã® HTML è¦ç´ ã¨åæ§ã«ã«ã¹ã¿ã åã使ç¨ãã¾ãã
<popup-info>
<!-- è¦ç´ ã®ä¸èº« -->
</popup-info>
屿§ã®å¤æ´ã¸ã®å¿ç
çµã¿è¾¼ã¿è¦ç´ ã¨åæ§ã«ãã«ã¹ã¿ã è¦ç´ ã HTML 屿§ã使ç¨ãã¦è¦ç´ ã®åä½ãè¨å®ãããã¨ãã§ãã¾ãã屿§ã广çã«ä½¿ç¨ããã«ã¯ãè¦ç´ ã屿§å¤ã®å¤æ´ã«å¯¾å¿ã§ããªããã°ãªãã¾ããããããå®ç¾ããã«ã¯ãã«ã¹ã¿ã è¦ç´ ãå®è£ ããã¯ã©ã¹ã«ä»¥ä¸ã®ã¡ã³ãã¼ã追å ããå¿ è¦ãããã¾ãã
observedAttributesã¨ããååã®éçããããã£ãããã¯ããã®è¦ç´ ã夿´éç¥ãå¿ è¦ã¨ãããã¹ã¦ã®å±æ§ã®ååãå«ãé åã§ãªããã°ãªãã¾ãããattributeChangedCallback()ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã®å®è£ ã
attributeChangedCallback() ã³ã¼ã«ããã¯ã¯ãè¦ç´ ã® observedAttributes ããããã£ã«ãªã¹ããããååã®å±æ§ã追å ãä¿®æ£ãåé¤ãç½®æããããã³ã«å¼ã³åºããã¾ãã
ã³ã¼ã«ããã¯ã«ã¯ 3 ã¤ã®å¼æ°ã渡ããã¾ãã
- 夿´ããã屿§ã®ååã
- 屿§ã®å¤ãå¤ã
- 屿§ã®æ°ããå¤ã
ä¾ãã°ããã®èªå¾çãªè¦ç´ 㯠size 屿§ãç£è¦ããå¤ã夿´ãããéã«æ°æ§ã®å¤ãè¨é²ãã¾ãã
// è¦ç´ ã®ããã®ã¯ã©ã¹ã使
class MyCustomElement extends HTMLElement {
static observedAttributes = ["size"];
constructor() {
super();
}
attributeChangedCallback(name, oldValue, newValue) {
console.log(
`屿§ ${name} 㯠${oldValue} ãã ${newValue} ã¸å¤æ´ããã¾ããã`,
);
}
}
customElements.define("my-custom-element", MyCustomElement);
è¦ç´ ã® HTML 宣è¨ã«ç£è¦ããã屿§ãå«ã¾ãã¦ããå ´åããã®å±æ§ãåæåãããå¾ã«ãè¦ç´ ã®å®£è¨ãæåã«è§£éãããæç¹ã§ attributeChangedCallback() ãå¼ã³åºããããã¨ã«
注æãã¦ãã ããã ãããã£ã¦ã以ä¸ã®ä¾ã§ã¯ããã¨ã屿§ããã®å¾å¤æ´ããããã¨ããªãã£ãã¨ãã¦ããDOM ãè§£éãããæç¹ã§ attributeChangedCallback() ãå¼ã³åºããã¾ãã
<my-custom-element size="100"></my-custom-element>
attributeChangedCallback() ã®ä½¿ç¨ã示ãå®å
¨ãªä¾ã«ã¤ãã¦ã¯ããã®ãã¼ã¸ã®ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ãåç
§ãã¦ãã ããã
ã«ã¹ã¿ã ç¶æ 㨠CSS ã®ã«ã¹ã¿ã ç¶æ æ¬ä¼¼ã¯ã©ã¹ã»ã¬ã¯ã¿ã¼
HTML è¦ç´ ã«çµã¿è¾¼ã¾ããè¦ç´ ã¯ããããã¼ãããç¡å¹ãããèªã¿åãå°ç¨ããªã©ãæ§ã ãªç¶æ ãåãã¾ãã ãããã®ç¶æ ã®ä¸é¨ã¯ãHTML ã¾ã㯠JavaScript ã使ç¨ãã¦å±æ§ã¨ãã¦è¨å®ã§ãã¾ãããå é¨çãªãã®ããããè¨å®ã§ããªããã®ãããã¾ãã å¤é¨ã¾ãã¯å é¨ã«é¢ãããããããã®ç¶æ ã«ã¯é常ãç¹å®ã®ç¶æ ã«ããè¦ç´ ã鏿ããã¹ã¿ã¤ã«ãé©ç¨ããããã«ä½¿ç¨ã§ãã対å¿ãã CSS æ¬ä¼¼ã¯ã©ã¹ãåå¨ãã¾ãã
ã¾ããèªå¾åã«ã¹ã¿ã è¦ç´ ï¼çµã¿è¾¼ã¿è¦ç´ ããã¼ã¹ã«ããè¦ç´ ãé¤ãï¼ã§ã¯ãæ¬ä¼¼ã¯ã©ã¹é¢æ° :state() ã使ç¨ãã¦ç¶æ
ãå®ç¾©ããããã«å¯¾ãã¦é¸æãè¡ããã¨ãã§ãã¾ãã
以ä¸ã®ã³ã¼ãã§ã¯ãå
é¨ç¶æ
"collapsed" ãæã¤èªå¾åã«ã¹ã¿ã è¦ç´ ã®ä¾ã使ç¨ãã¦ããã®åä½ã示ãã¦ãã¾ãã
collapsed ã®ç¶æ
ã¯ãè¦ç´ ã®å¤ããã¯è¦ããªãè«çå¤ããããã£ï¼ã»ãã¿ã¼ã¨ã²ãã¿ã¼ã¡ã½ããä»ãï¼ã¨ãã¦è¡¨ç¾ããã¾ãã
ãã®ç¶æ
ã CSS ã§é¸æã§ããããã«ããããã«ãã«ã¹ã¿ã è¦ç´ ã¯æåã®ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ HTMLElement.attachInternals() ãå¼ã³åºããElementInternals ãªãã¸ã§ã¯ããè£
çãã¾ããããã«ãããElementInternals.states ããããã£ãéã㦠CustomStateSet ã«ã¢ã¯ã»ã¹ã§ããããã«ãªãã¾ãã
ï¼å
é¨ã§ï¼æãããã¾ããç¶æ
ã®ã»ãã¿ã¼ã¯ãç¶æ
ã true ã§ããã° CustomStateSet ã«èå¥å hidden ã追å ããç¶æ
ã false ã§ããã°é¤å»ãã¾ãã èå¥åã¯åãªãæååã§ãããã®å ´åãhidden ã¨å¼ã³ã¾ããããcollapsed ã¨èªãã§ãåãããã«æ©è½ãã¾ãã
class MyCustomElement extends HTMLElement {
constructor() {
super();
this._internals = this.attachInternals();
}
get collapsed() {
return this._internals.states.has("hidden");
}
set collapsed(flag) {
if (flag) {
// èå¥åã®åå¨ããå ´å㯠"true" ã«å¯¾å¿ãã
this._internals.states.add("hidden");
} else {
// èå¥åãåå¨ããªãå ´å㯠"false" ã«å¯¾å¿ãã
this._internals.states.delete("hidden");
}
}
}
// ã«ã¹ã¿ã è¦ç´ ãç»é²
customElements.define("my-custom-element", MyCustomElement);
ã«ã¹ã¿ã è¦ç´ ã® CustomStateSet (this._internals.states) ã«è¿½å ãããèå¥åã使ç¨ãã¦ãè¦ç´ ã®ã«ã¹ã¿ã ç¶æ
ã¨ç
§åãããã¨ãã§ãã¾ãã
ããã¯ã:state() æ¬ä¼¼ã¯ã©ã¹ã«èå¥åãæ¸¡ãã¨ç
§åããã¾ãã
ä¾ãã°ãä¸è¨ã§ã¯ãhidden ã»ã¬ã¯ã¿ã¼ã使ç¨ãã¦ãhidden ç¶æ
ã trueï¼ãããã£ã¦ãè¦ç´ ãcollapsed ç¶æ
ï¼ã§ãããã¨ã鏿ããå¢çç·ãåé¤ãã¾ãã
my-custom-element {
border: dashed red;
}
my-custom-element:state(hidden) {
border: none;
}
:state() æ¬ä¼¼ã¯ã©ã¹ã :host() æ¬ä¼¼ã¯ã©ã¹é¢æ°å
ã§ä½¿ç¨ããã¨ãã«ã¹ã¿ã è¦ç´ ã®ã·ã£ã㦠DOM å
ã®ã«ã¹ã¿ã ç¶æ
ã¨ç
§åãããã¨ãã§ãã¾ãã
ããã«ã:state() æ¬ä¼¼ã¯ã©ã¹ã ::part() æ¬ä¼¼è¦ç´ ã®å¾ã§ä½¿ç¨ãããã¨ã§ãç¹å®ã®ç¶æ
ã«ããã«ã¹ã¿ã è¦ç´ ã®ã·ã£ãã¦ãã¼ãã¨ç
§åãããã¨ãã§ãã¾ãã
CustomStateSet ã«ã¯ããããã©ã®ããã«åä½ããã®ãã示ãããã¤ãã®ã©ã¤ããµã³ãã«ãããã¾ãã
ä¾
ãã®ã¬ã¤ãã®æ®ãã®é¨åã§ã¯ãããã¤ãã®ã«ã¹ã¿ã è¦ç´ ã®ä¾ãè¦ã¦ããã¾ãã ãããã®ä¾ã®ãã¹ã¦ãããã³ãã®ä»ã®ã½ã¼ã¹ã¯ãweb-components-examples ãªãã¸ããªã¼ã§åç §ã§ãã¾ããã¾ãããã¹ã¦ãã©ã¤ãã§ç¢ºèªããã«ã¯ãhttps://mdn.github.io/web-components-examples/ ã«ã¢ã¯ã»ã¹ãã¦ãã ããã
èªå¾ã«ã¹ã¿ã è¦ç´
ã¾ããèªå¾ã«ã¹ã¿ã è¦ç´ ã®ä¾ãè¦ã¦ã¿ã¾ãããã<popup-info> ã«ã¹ã¿ã è¦ç´ ã¯ãç»åã¢ã¤ã³ã³ã¨ããã¹ãæååã屿§ã¨ãã¦åããã¢ã¤ã³ã³ã«ãã©ã¼ã«ã¹ããã¨ãããã¹ãããããã¢ããæ
å ±ããã¯ã¹ã«è¡¨ç¤ºããããã«ã³ã³ããã¹ãå
ã®æ
å ±ãæä¾ãã¾ãã
æåã« HTMLElement ã¯ã©ã¹ãç¶æ¿ã㦠PopupInfo ã¨ããã¯ã©ã¹ãå®ç¾©ãã JavaScript ãã¡ã¤ã«ã§ãã
// è¦ç´ ã®ããã®ã¯ã©ã¹ã使
class PopupInfo extends HTMLElement {
constructor() {
// ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ super ãå¸¸ã«æåã«å¼ã³åºã
super();
}
connectedCallback() {
// ã·ã£ãã¦ã«ã¼ããçæ
const shadow = this.attachShadow({ mode: "open" });
// span è¦ç´ ãçæ
const wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
const icon = document.createElement("span");
icon.setAttribute("class", "icon");
icon.setAttribute("tabindex", 0);
const info = document.createElement("span");
info.setAttribute("class", "info");
// 屿§ã®ä¸èº«ãåå¾ããæ
å ± span ã®ä¸ã«å
¥ãã
const text = this.getAttribute("data-text");
info.textContent = text;
// ã¢ã¤ã³ã³ãæ¿å
¥
let imgUrl;
if (this.hasAttribute("img")) {
imgUrl = this.getAttribute("img");
} else {
imgUrl = "img/default.png";
}
const img = document.createElement("img");
img.src = imgUrl;
icon.appendChild(img);
// ããããã® CSS ãçæãã¦ã·ã£ã㦠DOM ã«é©ç¨
const style = document.createElement("style");
console.log(style.isConnected);
style.textContent = `
.wrapper {
position: relative;
}
.info {
font-size: 0.8rem;
width: 200px;
display: inline-block;
border: 1px solid black;
padding: 10px;
background: white;
border-radius: 10px;
opacity: 0;
transition: 0.6s all;
position: absolute;
bottom: 20px;
left: 10px;
z-index: 3;
}
img {
width: 1.2rem;
}
.icon:hover + .info, .icon:focus + .info {
opacity: 1;
}
`;
// çæè¦ç´ ãã·ã£ã㦠DOM ã«çµã³ã¤ãã
shadow.appendChild(style);
console.log(style.isConnected);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
åè¿°ã®ã³ã¼ãã¹ããããã¯ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã¼ (constructor()) ã®å®ç¾©ãå«ãã§ãã¾ããããã§ã¯å¸¸ã« super() ãæåã«å¼ã³åºããæ£ãããããã¿ã¤ããã§ã¼ã³ã確ç«ãããããã«ãã¾ãã
connectedCallback() ã¡ã½ããå
ã§ãè¦ç´ ã DOM ã«æ¥ç¶ãããéã«ãã®è¦ç´ ãæã¤ãã¹ã¦ã®æ©è½ãå®ç¾©ãã¾ãããã®ä¾ã§ã¯ãã·ã£ãã¦ã«ã¼ããã«ã¹ã¿ã è¦ç´ ã«å²ãå½ã¦ãDOM æä½ã使ç¨ãã¦è¦ç´ ã®å
é¨ã·ã£ãã¦ã«ã¼ãæ§é ã使ãã¾ãï¼ããã¦ã·ã£ãã¦ã«ã¼ãã«å²ãå½ã¦ã¾ãï¼ãæå¾ã«ãã·ã£ãã¦ã«ã¼ãã«ããã¤ãã® CSS ãå²ãå½ã¦ã¦ã¹ã¿ã¤ã«è¨å®ãã¾ããè¦ç´ ã®å±æ§ã¯ DOM ã«æ¥ç¶ãããã¾ã§å©ç¨ã§ããªããããã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯å¦çã¯ãã¾ãããã¾ããã
æå¾ã«ãã«ã¹ã¿ã è¦ç´ ã CustomElementRegistry ã«ç»é²ãã¾ããåè¿°ã® define() ã使ç¨ãã¦ã弿°ã§è¦ç´ åã¨ãã®æ©è½ãå®ç¾©ããã¯ã©ã¹åãæå®ãã¾ãã
customElements.define("popup-info", PopupInfo);
ããã«ãã£ã¦è¦ç´ ããã¼ã¸ã§ä½¿ããããã«ãªãã¾ããã HTML å ã§ä¸è¨ã®ããã«ä½¿ç¨ãããã¨ãã§ãã¾ãã
<popup-info
img="img/alt.png"
data-text="Your card validation code (CVC)
is an extra security feature â it is the last 3 or 4 numbers on the
back of your card."></popup-info>
å é¨ã¹ã¿ã¤ã«ã¨å¤é¨ã¹ã¿ã¤ã«
ä¸è¨ã®ä¾ã§ã¯ã<style> è¦ç´ ãç¨ãã¦ã·ã£ã㦠DOM ã«ã¹ã¿ã¤ã«ãé©ç¨ãã¾ãããã代ããã« <link> è¦ç´ ããå¤é¨ã¹ã¿ã¤ã«ã·ã¼ããåç
§ãããã¨ãå¯è½ã§ãããã®ä¾ã§ã¯ãå¤é¨ã¹ã¿ã¤ã«ã·ã¼ãã使ç¨ããããã« <popup-info> ã«ã¹ã¿ã è¦ç´ ã夿´ãã¾ãã
ãã¡ããã¯ã©ã¹å®ç¾©ã§ãã
// è¦ç´ ã®ããã®ã¯ã©ã¹ã使
class PopupInfo extends HTMLElement {
constructor() {
// ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ super ãå¸¸ã«æåã«å¼ã³åºã
super();
}
connectedCallback() {
// ã·ã£ãã¦ã«ã¼ããçæ
const shadow = this.attachShadow({ mode: "open" });
// span è¦ç´ ãçæ
const wrapper = document.createElement("span");
wrapper.setAttribute("class", "wrapper");
const icon = document.createElement("span");
icon.setAttribute("class", "icon");
icon.setAttribute("tabindex", 0);
const info = document.createElement("span");
info.setAttribute("class", "info");
// 屿§ã®ä¸èº«ãåå¾ããæ
å ± span ã®ä¸ã«å
¥ãã
const text = this.getAttribute("data-text");
info.textContent = text;
// ã¢ã¤ã³ã³ãæ¿å
¥
let imgUrl;
if (this.hasAttribute("img")) {
imgUrl = this.getAttribute("img");
} else {
imgUrl = "img/default.png";
}
const img = document.createElement("img");
img.src = imgUrl;
icon.appendChild(img);
// å¤é¨ã¹ã¿ã¤ã«ã·ã¼ããã·ã£ã㦠DOM ã«é©ç¨
const linkElem = document.createElement("link");
linkElem.setAttribute("rel", "stylesheet");
linkElem.setAttribute("href", "style.css");
// çæããè¦ç´ ãã·ã£ã㦠DOM ã«çµã³ã¤ãã
shadow.appendChild(linkElem);
shadow.appendChild(wrapper);
wrapper.appendChild(icon);
wrapper.appendChild(info);
}
}
ããã¯ãå
ã® <popup-info> ã®ä¾ã¨ã»ã¼åãã§ãããå¤é¨ã¹ã¿ã¤ã«ã·ã¼ãã«ãªã³ã¯ããããã«ãã·ã£ã㦠DOM ã«è¿½å ãã <link> è¦ç´ ã使ç¨ãã¦ããç¹ãç°ãªãã¾ãã
ãªãã <link> è¦ç´ ã¯ã·ã£ãã¦ã«ã¼ãã®æç»ããããã¯ããªãã®ã§ãã¹ã¿ã¤ã«ã·ã¼ãã®ãã¼ãä¸ã«ã¹ã¿ã¤ã«ä»ãããã¦ããªãã³ã³ãã³ã (FOUC) ãä¸ç¬è¡¨ç¤ºããããããããªããã¨ã«æ³¨æãã¦ãã ããã
æè¿ã®ãã©ã¦ã¶ã¼ã®å¤ãã¯ãå
±éã®ãã¼ãããã¯ãã¼ã³ãããããããã¯åä¸ã®ããã¹ããæã¤ <style> ã¿ã°ã«å¯¾ãã¦ãåä¸ã®ãããã³ã°ã¹ã¿ã¤ã«ã·ã¼ããå
±æã§ããããã«ããæé©åãå®è£
ãã¦ãã¾ãããã®æé©åã«ãã£ã¦ãå¤é¨ã¹ã¿ã¤ã«ã§ãå
é¨ã¹ã¿ã¤ã«ã§ãæ§è½ã¯åç¨åº¦ã«ãªãã¯ãã§ãã
ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´
ããã§ããã 1 ã¤ã®çµã¿è¾¼ã¿è¦ç´ ã®ä¾ãè¦ã¦ã¿ã¾ãããããã®ä¾ã¯ãçµã¿è¾¼ã¿ã® <ul> è¦ç´ ãæ¡å¼µãã¦ããªã¹ãã¢ã¤ãã ãå±éã»åç´ããããã«ãã¾ãã
ã¡ã¢:
ã«ã¹ã¿ã çµã¿è¾¼ã¿è¦ç´ ã®å®è£
ã«é¢ããæ³¨æäºé
ã«ã¤ãã¦ã¯ãis 屿§ã®ãªãã¡ã¬ã³ã¹ãåç
§ãã¦ãã ããã
ã¾ãå§ãã«ãããã¾ã§ã¨åæ§ã®æ¹æ³ã§ã¯ã©ã¹è¦ç´ ãå®ç¾©ãã¾ãã
// è¦ç´ ã®ããã®ã¯ã©ã¹ã使
class ExpandingList extends HTMLUListElement {
constructor() {
// ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ super ãå¸¸ã«æåã«å¼ã³åºã
// super() ã®è¿å¤ã¯ãã®è¦ç´ ã¸ã®åç
§
self = super();
}
connectedCallback() {
// ãã®ã«ã¹ã¿ã ul è¦ç´ ã®åã§ãã ul ããã³ li è¦ç´ ãåå¾ãã
// li è¦ç´ ã¯ããã®ä¸ã« ul ãããå ´åãã³ã³ããã¼ã¨ãã¦æ©è½ãã
const uls = Array.from(self.querySelectorAll("ul"));
const lis = Array.from(self.querySelectorAll("li"));
// ãã¹ã¦ã®åã® ul ãé ã
// ãããã®ãªã¹ãã¯ãã¦ã¼ã¶ã¼ãä¸ä½ã¬ãã«ã®ã³ã³ããã¼ãã¯ãªãã¯ããã¨ãã«è¡¨ç¤ºããã
uls.forEach((ul) => {
ul.style.display = "none";
});
// ulå
ã®liè¦ç´ ãããããè¦ã¦ãã
lis.forEach((li) => {
// ãã® li ã« ul ãåè¦ç´ ã¨ãã¦ããå ´åãã¯ãªãã¯ãã³ãã©ã¼ã追å ãã
if (li.querySelectorAll("ul").length > 0) {
// ã¹ã¿ã¤ã«è¨å®ã§ä½¿ç¨ã§ãã屿§ã追å ãã
// éãã»éããã¢ã¤ã³ã³ã表示ããã
li.setAttribute("class", "closed");
// li è¦ç´ ã®ããã¹ããæ°ãã span è¦ç´ ã§å²ããã¨ã§ã
// span ã«ã¹ã¿ã¤ã«ãã¤ãã³ããã³ãã©ã¼ãå²ãå½ã¦ããã¨ãã§ãã
const childText = li.childNodes[0];
const newSpan = document.createElement("span");
// li ãã span ã«ããã¹ããã³ãã¼ããã«ã¼ã½ã«ã¹ã¿ã¤ã«ãè¨å®
newSpan.textContent = childText.textContent;
newSpan.style.cursor = "pointer";
// ãã® span ã«ã¯ãªãã¯ãã³ãã©ã¼ã追å
newSpan.addEventListener("click", (e) => {
// span è¦ç´ ã®æ¬¡å
å¼è¦ç´ 㯠ul ã§ããã¯ã
const nextUl = e.target.nextElementSibling;
// è¡¨ç¤ºç¶æ
ãåãæ¿ããul ã® class 屿§ãæ´æ°
if (nextUl.style.display === "block") {
nextUl.style.display = "none";
nextUl.parentNode.setAttribute("class", "closed");
} else {
nextUl.style.display = "block";
nextUl.parentNode.setAttribute("class", "open");
}
});
// span ã追å ããli ãã裸ã®ããã¹ããã¼ããé¤å»
childText.parentNode.insertBefore(newSpan, childText);
childText.parentNode.removeChild(childText);
}
});
}
}
ãªããä»å㯠HTMLElement ã§ã¯ãªããHTMLUListElement ãæ¡å¼µãã¦ãã¾ãã ã¤ã¾ãããªã¹ãã®æ¢å®ã®åä½ãå¾ãããç¬èªã®ã«ã¹ã¿ãã¤ãºã®ã¿ãå®è£
ããã°ããã¨ãããã¨ã§ãã
ååã¨åæ§ã«ãã³ã¼ãã®ã»ã¨ãã©ã¯ connectedCallback() ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯å
ã«ããã¾ãã
次ã«ãååã¨åæ§ã« define() ã¡ã½ããã使ç¨ãã¦è¦ç´ ãç»é²ãã¾ãããä»åã¯ãã«ã¹ã¿ã è¦ç´ ãç¶æ¿ããè¦ç´ ã®è©³ç´°ãè¨è¼ãã options ãªãã¸ã§ã¯ããå«ãã¾ãã
customElements.define("expanding-list", ExpandingList, { extends: "ul" });
ã¦ã§ãææ¸å ã§çµã¿è¾¼ã¿è¦ç´ ã使ç¨ããã¨ãã¾ãå°ãéã£ãè¦ãæ¹ã«ãªãã¾ãã
<ul is="expanding-list">
â¦
</ul>
é常ã®ããã« <ul> ã使ç¨ãã¦ãã¾ãããã«ã¹ã¿ã è¦ç´ ã®ååã is 屿§ã§æå®ããã¦ãã¾ãã
ãã®å ´åãDOM ãå®å
¨ã«è§£éãããå¾ã«ã«ã¹ã¿ã è¦ç´ ãå®ç¾©ããã¹ã¯ãªãããå®è¡ãããããã«ä¿è¨¼ããå¿
è¦ãããã¾ããconnectedCallback() ã¯å±éããããªã¹ãã DOM ã«è¿½å ãããã¨åæã«å¼ã³åºããã¾ããããã®æç¹ã§ã¯åè¦ç´ ã¯ã¾ã 追å ããã¦ããªããããquerySelectorAll() ã®å¼ã³åºãã§ã¯ä½ãè¦ã¤ããã¾ããããããä¿è¨¼ããä¸ã¤ã®æ¹æ³ã¯ãã¹ã¯ãªãããè¨è¼ããè¡ã« defer 屿§ã追å ãããã¨ã§ãã
<script src="main.js" defer></script>
ã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯
ããã¾ã§ã¯ãconnectedCallback() ã¨ããã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã 1 ã¤ã ãåä½ãã¦ããã®ãè¦ã¦ãã¾ãããæå¾ã®ä¾ã§ãã <custom-square> ã§ã¯ãä»ã«ãããã¤ãè¦ã¦ããã¾ãããã®ä¾ã§ã¯ãèªå¾åã®ã«ã¹ã¿ã è¦ç´ <custom-square> ãç´¹ä»ãã¾ããããã¯ãååä»ãã® 2 ã¤ã®å±æ§ "size" ããã³ "color" ã«ãã£ã¦ãµã¤ãºã¨è²ã決å®ãããåè§å½¢ãæç»ãã¾ãã
ã¯ã©ã¹ã®ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ãè¦ç´ ã«ã·ã£ã㦠DOM ãå²ãå½ã¦ã空㮠<div> ããã³ <style> è¦ç´ ãã·ã£ãã¦ã«ã¼ãã«è¿½å ãã¾ãã
class Square extends HTMLElement {
// â¦
constructor() {
// ã³ã³ã¹ãã©ã¯ã¿ã¼ã§ã¯ super ãå¸¸ã«æåã«å¼ã³åºã
super();
const shadow = this.attachShadow({ mode: "open" });
const div = document.createElement("div");
const style = document.createElement("style");
shadow.appendChild(style);
shadow.appendChild(div);
}
// â¦
}
ãã®ä¾ã®ä¸»è¦ãªæ©è½ã¯ updateStyle() ã§ããããã¯è¦ç´ ãåå¾ããã·ã£ãã¦ã«ã¼ããåå¾ãããã® <style> è¦ç´ ãè¦ã¤ãã¦ãwidth, height, background-color ããã®ã¹ã¿ã¤ã«ã«è¿½å ãã¾ãã
function updateStyle(elem) {
const shadow = elem.shadowRoot;
shadow.querySelector("style").textContent = `
div {
width: ${elem.getAttribute("size")}px;
height: ${elem.getAttribute("size")}px;
background-color: ${elem.getAttribute("color")};
}
`;
}
å®éã®æ´æ°ã¯ãã¹ã¦ãã¡ã½ããã¨ãã¦ã¯ã©ã¹å®ç¾©å
ã«é
ç½®ããã¦ããã©ã¤ããµã¤ã¯ã«ã³ã¼ã«ããã¯ã«ãã£ã¦å¦çããã¾ãã connectedCallback() ã¯ãè¦ç´ ã DOM ã«è¿½å ããããã³ã«å®è¡ããã¾ããããã§ã¯ã updateStyle() 颿°ãå®è¡ãã¦ãæ£æ¹å½¢ããã®å±æ§ã§å®ç¾©ãããã¹ã¿ã¤ã«ã«ãªã£ã¦ãããã¨ã確èªãã¾ãã
class Square extends HTMLElement {
// â¦
connectedCallback() {
console.log("ã«ã¹ã¿ã ç©å½¢è¦ç´ ããã¼ã¸ã«è¿½å ããã¾ããã");
updateStyle(this);
}
// â¦
}
disconnectedCallback() ããã³ adoptedCallback() ã³ã¼ã«ããã¯ã¯ãè¦ç´ ã DOM ããåé¤ãããããå¥ã®ãã¼ã¸ã«ç§»åãããã¨ãã«éç¥ããåç´ãªã¡ãã»ã¼ã¸ãã³ã³ã½ã¼ã«ã«è¨é²ãã¾ãã
class Square extends HTMLElement {
// â¦
disconnectedCallback() {
console.log("ã«ã¹ã¿ã ç©å½¢è¦ç´ ããã¼ã¸ããåé¤ããã¾ããã");
}
adoptedCallback() {
console.log("ã«ã¹ã¿ã ç©å½¢è¦ç´ ãæ°ãããã¼ã¸ã«ç§»åãã¾ããã");
}
// â¦
}
attributeChangedCallback() ã³ã¼ã«ããã¯ã¯ãè¦ç´ ã®å±æ§ã® 1 ã¤ãä½ããã®æ¹æ³ã§å¤æ´ããããã³ã«å®è¡ããã¾ãããã®å¼æ°ãããããããã«ã屿§ã屿§ã®ååãããã³å¤ã屿§å¤ã¨æ°ãã屿§å¤ãåå¥ã«æä½ãããã¨ãã§ãã¾ãããã ãããã®å ´åã¯ãupdateStyle() 颿°ãå度å®è¡ãã¦ãæ°ããå¤ã«å¾ã£ã¦æ£æ¹å½¢ã®ã¹ã¿ã¤ã«ãæ´æ°ãããããã«ãã¾ãã
class Square extends HTMLElement {
// â¦
attributeChangedCallback(name, oldValue, newValue) {
console.log("ã«ã¹ã¿ã ç©å½¢è¦ç´ ã®å±æ§ã夿´ããã¾ããã");
updateStyle(this);
}
// â¦
}
ãã屿§ã夿´ãããã¨ãã«èµ·åãã attributeChangedCallback() ã³ã¼ã«ããã¯ãåå¾ããã«ã¯ããã®å±æ§ãç£è¦ããå¿
è¦ããããã¨ã«æ³¨æãã¦ãã ãããããã¯ãã«ã¹ã¿ã è¦ç´ ã¯ã©ã¹å
ã§ static get observedAttributes() ã¡ã½ãããå®ç¾©ãããã¨ã«ãã£ã¦è¡ããã¾ããããã¯ãç£è¦ããã屿§ã®ååãå«ãé
åãè¿ãããã«ãã¦ãã ããã
class Square extends HTMLElement {
// â¦
static get observedAttributes() {
return ["color", "size"];
}
// â¦
}