Web Componentsに触れる

Web Componentsに触れる:


0. WebComponentsって?

Web Components は、再利用可能なカスタム要素を作成し、ウェブアプリの中で利用するための、一連のテクノロジーです。
引用元:https://developer.mozilla.org/ja/docs/Web/Web_Components

一連のテクノロジーの主な中身

- HTML Templates

- HTML Imports

- Shadow DOM

- Custom Elements

これらを一つづつ、さらっと表面をなぞっていく

※見やすくするためにhtmlでは、html要素とhead要素を使っていません


1. HTML Templates

再利用可能なHTML要素

index.html

<body> 
  <template> 
    <h1>Hello HTML Templates</h1> 
    <img src=""> 
  </template> 
  <script src="main.js"></script> 
</body> 
この時点では、なにも表示されない




JSでtemplateをクローンしてbodyにappendChildする
main.js

const TEMPLATE = document.querySelector('template'); 
const CLONE = document.importNode(TEMPLATE.content, true); 
document.body.appendChild(CLONE); 





template自体を表示させるんじゃなくて、いったんcloneして生成するのがキモ。

img src(unknow)になってるのでsrcをつけてみる
main.js

const TEMPLATE = document.querySelector('template'); 
TEMPLATE.content.querySelector('img').src = 'https://dummyimage.com/99'; 
const CLONE = document.importNode(TEMPLATE.content, true); 
document.body.appendChild(CLONE); 
template要素.contentに対してquerySelectorする





2. HTML Imports

外部HTMLを読み込む

foo.html

<h1>Hello HTML Imports</h1> 
index.html

<body> 
  <link rel="import" href="foo.html"> 
  <script src="main.js"></script> 
</body> 
main.js

const IMPORT = document.querySelector('link[rel="import"]').import; 
const HEADER = IMPORT.querySelector('h1'); 
document.body.appendChild(HEADER.cloneNode(true)); 
インポートしたfoo.htmlからh1を取り出してbodyにappendChildしている。






HTML TemplateをHTML Importsする

template.html

<template> 
  <h1>Hello HTML Templates from template.html</h1> 
  <img src=""> 
</template> 
 
index.html

<body> 
  <link rel="import" href="template.html"> 
  <script src="main.js"></script> 
</body> 
main.js

//HTML imports 
const IMPORT = document.querySelector('link[rel="import"]').import; 
 
//HTML template 
const TEMPLATE = IMPORT.querySelector('template'); 
TEMPLATE.content.querySelector('img').src = 'https://dummyimage.com/99'; 
 
//クローンを作成してbodyに生やす 
const CLONE = document.importNode(TEMPLATE.content, true); 
document.body.appendChild(CLONE); 




※import元のhtmlの名前空間(idやclass)にはスコープが生成されるが、styleはそうでないので注意
template.html

<template> 
  <style> 
    h1 { 
      color: red; 
    } 
  </style> 
  <h1>Hello from template.html</h1> 
</template> 
index.html

<body> 
  <h1>Hello from index.html</h1> 
  <link rel="import" href="template.html"> 
  <script src="main.js"></script> 
</body> 
main.js

const IMPORT = document.querySelector('link[rel="import"]').import; 
const TEMPLATE = IMPORT.querySelector('template'); 
const CLONE = document.importNode(TEMPLATE.content, true); 
document.body.appendChild(CLONE); 




index.htmlにも、template.htmlのスタイルが適用される。

styleの名前空間を汚したくない!

→Shadow DOMで解決


3. Shadow DOM

カプセル化してくれるやつ

index.html

<body> 
  <h1>Hello</h1> 
  <script src="main.js"></script> 
</body> 
main.js

const SHADOW = document.querySelector('h1').createShadowRoot(); 
SHADOW.textContent = 'Hello Shadow DOM'; 




一見何の変哲もないが、






ShadowDOMは表示だけを担当し、JSから参照する場合は、元々の値が返される。

使いみちは?

→ShadowDOMはstyleを含めたスコープを持つ(カプセル化と言う)

ということで、


HTML TemplateをHTML ImportsしてShadowDOMで出力する

template.html

<template> 
  <style> 
h1 { 
  color: red; 
} 
  </style> 
  <h1>Hello from template.html</h1> 
</template> 
index.html

<body> 
  <h1>index.html</h1> 
  <div id='for_shadow'></div> 
  <link rel="import" href="template.html"> 
  <script src="main.js"></script> 
</body>   
main.js

//HTML imports 
const IMPORT = document.querySelector('link[rel="import"]').import; 
 
//HTML template 
const TEMPLATE = IMPORT.querySelector('template'); 
const CLONE = document.importNode(TEMPLATE.content, true); 
 
//Shadow DOM 
const SHADOW = document.querySelector('#for_shadow').createShadowRoot(); 
SHADOW.appendChild(CLONE); 
 
//DOMアクセス 
console.log(document.querySelector('#for_shadow').shadowRoot); 
console.log(document.querySelector('#for_shadow::shadow h1')); 




無事、styleの名前空間を分離することができた


4. Custom Elements

タグを自作

いきなり、全部の合わせ技
template.html

<template> 
  <h1>Hello from template.html as x-card</h1> 
</template> 
index.html

<body> 
  <link rel="import" href="template.html"> 
  <script src="main.js"></script> 
</body> 
main.js

//Custom Elementsを定義 
const card = class extends HTMLElement { 
  connectedCallback() { //お約束 
//html import 
const IMPORT = document.querySelector('link[rel="import"]').import; 
 
//html template 
const TEMPLATE = IMPORT.querySelector('template'); 
const CLONE = document.importNode(TEMPLATE.content, true); 
 
//Shadow DOM 
this.createShadowRoot().appendChild(CLONE); 
  } 
}; 
 
//x-cardタグにcardクラスを登録 
window.customElements.define('x-card', card); 
 
//bodyに生成 
document.body.appendChild(new card()); 
![](https://d2mxuefqeaa7sj.cloudfront.net/s_2DAEA40B10D7CD0BC867F66D74B2266921463141871BDD2BA2941A20F0A64C24_1539513878920_image.png) 


5. ブラウザの対応状況

2018/10/14時点ではブラウザの対応状況がマチマチなので注意

HTML ImportsとShadow DOMにいたっては草案(Working Draft: WD)段階

https://caniuse.com/#feat=template



https://caniuse.com/#feat=imports

https://caniuse.com/#feat=shadowdomv1

https://caniuse.com/#feat=custom-elementsv1


コメント

このブログの人気の投稿

投稿時間:2021-06-17 05:05:34 RSSフィード2021-06-17 05:00 分まとめ(1274件)

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2020-12-01 09:41:49 RSSフィード2020-12-01 09:00 分まとめ(69件)