0. WebComponentsって?
Web Components は、再利用可能なカスタム要素を作成し、ウェブアプリの中で利用するための、一連のテクノロジーです。
引用元:https://developer.mozilla.org/ja/docs/Web/Web_Components
一連のテクノロジーの主な中身
これらを一つづつ、さらっと表面をなぞっていく
※見やすくするためにhtmlでは、html要素とhead要素を使っていません
1. HTML Templates
再利用可能なHTML要素
<body>
<template>
<h1>Hello HTML Templates</h1>
<img src="">
</template>
<script src="main.js"></script>
</body>
JSでtemplateをクローンしてbodyにappendChildする
const TEMPLATE = document.querySelector('template');
const CLONE = document.importNode(TEMPLATE.content, true);
document.body.appendChild(CLONE);
template自体を表示させるんじゃなくて、いったんcloneして生成するのがキモ。
img src(unknow)になってるのでsrcをつけてみる
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を読み込む
<h1>Hello HTML Imports</h1>
<body>
<link rel="import" href="foo.html">
<script src="main.js"></script>
</body>
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>
<h1>Hello HTML Templates from template.html</h1>
<img src="">
</template>
<body>
<link rel="import" href="template.html">
<script src="main.js"></script>
</body>
//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>
<style>
h1 {
color: red;
}
</style>
<h1>Hello from template.html</h1>
</template>
<body>
<h1>Hello from index.html</h1>
<link rel="import" href="template.html">
<script src="main.js"></script>
</body>
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
カプセル化してくれるやつ
<body>
<h1>Hello</h1>
<script src="main.js"></script>
</body>
const SHADOW = document.querySelector('h1').createShadowRoot();
SHADOW.textContent = 'Hello Shadow DOM';
ShadowDOMは表示だけを担当し、JSから参照する場合は、元々の値が返される。
使いみちは?
→ShadowDOMはstyleを含めたスコープを持つ(カプセル化と言う)
ということで、
HTML TemplateをHTML ImportsしてShadowDOMで出力する
<template>
<style>
h1 {
color: red;
}
</style>
<h1>Hello from template.html</h1>
</template>
<body>
<h1>index.html</h1>
<div id='for_shadow'></div>
<link rel="import" href="template.html">
<script src="main.js"></script>
</body>
//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'));
4. Custom Elements
タグを自作
いきなり、全部の合わせ技
<template>
<h1>Hello from template.html as x-card</h1>
</template>
<body>
<link rel="import" href="template.html">
<script src="main.js"></script>
</body>
//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());
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