albatrosary's blog

UI/UXとエンタープライズシステム

【続】Web標準だけでHTMLを部品化するWeb Componentsを試してみる

前回のブログ「Web標準だけでHTMLを部品化するWeb Componentsを試してみる - albatrosary's blog」でWeb Componentsを部品化しましたが2点問題がありました。

  • 親HTMLにJavaScriptを書いているため冗長的
  • Custom Elementsの恩恵を受けていない

丁度「WebComponentsでデバイスピクセル比を表示するカスタム要素を作った - コンピュータクワガタ」でそれらをうまく実装していましたので、前回のモジュールを同じようなやり方で実装し直します。

Shadow DOMサンプルの作り直し

作り直すポイントは

  • 「document.registerElement('x-component');」でカスタムタグを定義している
  • importでアクティベーションさせるためにはtemplateタグの外にJavaScriptを書くこと

です。かなりスマートな「部品」になったと思います。

<template>
<div>Template used</div>
<div>hoge</div>
<style>
div {
font-size: 20px;
}
</style>
<script>
console.log("テンプレート");
</script>
</template>
<!-- アクティベート -->
<script>
console.log("アクティベート");
var customElementName = 'x-component';
document.registerElement(customElementName);
var owner = document.currentScript.ownerDocument;
var templates = owner.querySelector('template');
if(templates) {
var contents = templates.content;
var xcomponents = document.querySelectorAll(customElementName);
for (i = 0; i < xcomponents.length; i++) {
// ShadowDomを作成し注入
xcomponents[i].createShadowRoot().appendChild(contents.cloneNode(true));
}
}
</script>

 

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
<link rel="import" href="components/x-component.html">
<style>
div {
font-size: 10px;
}
</style>
</head>
<body>
<div>ここはtemplateの外</div>
<x-component></x-component>
<x-component></x-component>
<x-component></x-component>
<div>ここはtemplateの外</div>
</body>
</html>

f:id:albatrosary:20140724134613p:plain

ログに「アクティベート」と「テンプレート」という文字が表示されているのでJavaScriptの実行順が理解できると思います。テンプレートにアクティベート部分のモジュールを移動させたので親HTMLは綺麗になったがテンプレートが冗長的になっているような・・。

更に変更

ということで更に変更しました。カスタムタグにShadow DOMを設定するモジュールを外だしにしています。それぞれのファイルは下記の通りです。

<!doctype html>
<html class="no-js">
<head>
<meta charset="utf-8">
<title>Web Components</title>
<link rel="shortcut icon" href="/favicon.ico">
<link rel="import" href="components/x-component2.html">
<link rel="import" href="components/x-component3.html">
<style>
div {
font-size: 10px;
}
</style>
</head>
<body>
<div>ここはtemplateの外</div>
<x-component2></x-component2>
<x-component2></x-component2>
<x-component2></x-component2>
<x-component3></x-component3>
<div>ここはtemplateの外</div>
  <script src="scripts/components.js"></script>
</body>
</html> 
scripts/components.js
'use strict';
(function (){
var imports = document.querySelectorAll('link[rel="import"]');
for (var j = 0; j < imports.length; j++) {
var templates = imports[j].import.querySelector('template');
if(templates) {
var contents = templates.content;
var customElementName = templates.getAttribute('id');
document.registerElement(customElementName);
var xcomponents = document.querySelectorAll(customElementName);
for (var i = 0; i < xcomponents.length; i++) {
xcomponents[i].createShadowRoot().appendChild(contents.cloneNode(true));
}
}
}
})();
components/x-component2.html
<template id="x-component2">
<div>Template used 2</div>
<div>hoge</div>
<style>
div {
font-size: 20px;
}
</style>
<script>
console.log("テンプレート");
</script>
</template>
components/x-component3.html
<template id="x-component3">
<div>Template used 3</div>
<div>hoge</div>
<style>
div {
font-size: 20px;
}
</style>
<script>
console.log("テンプレート");
</script>
</template>

最後に

だいぶ迷走していますが、これから色々な方のブログ等で勉強させて頂きスマートなWeb Components実装が出来ればと思います。