Web ComponentsはじめるならPolymerで

ご注意

この記事は 2015年12月16日 に書かれたものです。内容が古い可能性がありますのでご注意ください。

次世代のWebを先取りするPolymer

Webサイトの制作に関して、UIの部品化というのは非常に重要なテーマです。 一度、自分や他人が作ったUIを再利用することができると、効率性や保守性の観点で大きなメリットがあるからです。 PolymerはWeb UIの作成や再利用を、より簡略化することを目的として、Googleが開発したJavascriptライブラリです。 これまでにUIの部品化に関して、最も成功した例にjQuery UIやTwitter Bootstrapなどがありますが、Polymerがそれらと異なる点は、次世代のWeb標準になることが予定されている、Web UI部品化技術であるWeb componentsを基礎としていることです。 そもそも、Web components自体もGoogleが最初に提唱したことから始まり、現在、W3Cで仕様策定が進められているものです。ただし、Web Componentsをサポートしているブラウザは、まだほとんどありません。 Polymerの利点の一つは、Web Componentsに対応していないブラウザでも、Web Componentsを利用できるPolyfillライブラリ()であるということです。さらに、PolymerはWeb Componentsよりもさらに使いやすいインターフェースやさらなる機能を提供する提供してくれます。 ※ Polyfillとは、古いブラウザで対応していない機能があったときに、そのブラウザで対応している既存技術を組み合わせて、同等のものを提供することを指します。 本記事では、まずはPolymerを使って、Web Componentsに入門しようという趣旨で、初心者向けに、Polymerのメリットの紹介し、サンプルコードを通じてPolymerの基本を解説していきます。
  1. Web Componentsの概要 – Web Componentsについて、簡単に紹介します
  2. Polymerを用いる3つのメリット – Polymerを用いると何がいいのかを紹介します
  3. 早速Polymerを使ってみる – Polymerをインストールし、単純なカスタム要素の定義してみます
  4. Polymerを使うとカスタム要素をシンプルに定義できる – 同じ内容のカスタム要素を、Polymerを使わない、通常のWeb Componentsで定義した場合のコードと比較して、Polymerを使うとどれだけコードが簡潔になるかを確認します
  5. Polymerのいろいろな機能を試す – サンプルコードを少しずつ発展させて、Polymerの機能の一部を紹介します
  6. いくつかの補足とまとめ – 比較的重要だけれども、紹介できなかったトピックについて、簡単に補足します
登場するサンプルコードは単純ではありますが、延長線上に実践的に使えるコンポーネントを想像できるようなものにしたつもりです。

Web Componentsの概要

Web Componentsとは、HTMLやCSSにスコープが存在しないことなどに起因する、WEB構成要素の部品化、再利用化に関する問題を解決するために提唱された次世代のWEB標準仕様です。Web Componentsでは、以下の4つの技術を組み合わせて、HTML, CSS, JavaScriptをカプセル化、コンポーネント化を実現します()。
  • Custom Elements – 独自のカスタム要素をユーザーが定義することを可能にする
  • Shadow DOM – HTMLやCSSに隔離されたスコープを形成し、部品をカプセル化する
  • Templates – カスタム要素の雛形となるHTMLを定義する
  • HTML Imports – 断片化したHTMLファイルをロードする
※ Web Components自体もかなり大きなトピックなのですが、ここでは、詳しくは解説しません。日本語のサイトでは、下記のサイトが詳しいので参照してください。 Web Componentsの基本的な使い方・まとめ ところで、Web Componentsの4つの技術要素のほとんどが、まだ仕様策定中というステータスであり()、全てに対応しているブラウザは少ないです。現状のところ、ChromeやChromiumベースのOperaくらいでしょう。FirefoxはHTML Importsを実装することに否定的なようです。 ※ ステータスはW3C公式ページで確認できます。 Web Components Current Status

Polymerを用いる3つのメリット

Polymerは、Web Componentsをより使いやすくするために作られたライブラリであり、また、Web Componentsにはない様々な機能を提供し、開発者がより良い部品を作成するのを手助けしてくれます。Polymerを用いる主なメリットは、以下のようなものです。

クロスプラットフォーム

Web ComponentsはWEBにおけるUIの部品化、再利用化を推し進める、次世代の標準仕様になると期待されていますが、現状では、Custom Elements, Shadow DOM, Templates, HTML Importsの全てに対応しているブラウザは少ないです。しかし、Polymerを使えば、ブラウザ間・マルチデバイス間(タブレットやスマフォ等)の実装の差を埋めてくれるので、各ブラウザでWeb Componentsを使うことができます()。 ※ Polymerは、同じくPolymerチームが開発したwebcomponents.jsというWeb ComponentsのPolyfillライブラリを利用しています。

簡潔な構文、強力な機能

Polymerはカスタム要素を定義する、より簡潔な構文を提供してくれます。また、データバインディングなどのWeb Componentsにはない機能を持っており、開発者を強力にサポートしてくれます。これらの点については、後でもう少し詳しく解説します。

高速化、軽量化されたコード

Polymer1.0では、webcomponents.jsのShadow DOM Polyfillの代わりに、Shady DOMと名付けられたより軽量で高速な実装を用いています。ただし、これはShadow DOMの完全な エミュレートではないため、少し注意が必要です。この点については、本記事の最後で少しだけ補足します。

早速Polymerを使ってみる

Polymerをインストールする

Polymerの公式サイトではBower()を使ってインストールすることを推奨しています。 Bowerをインストールしていない場合は、Bower公式サイトを参照し、インストールしてください。Bowerのインストールができたら、プロジェクトフォルダを作成し、そのフォルダ直下で以下のコマンドを実行してください。 ※ フロントエンド用のパッケージマネージャ、JavaでいうMavenやGradleのようなものです。

$ bower init

すると、対話的にいくつかの質問が表示されます。ここでは、とりあえずエンターキーだけを押してデフォルトのままにしましょう。すべての質問に答えると、bower.jsonが作成されます。 次に、以下のコマンドを実行すると、Polymerを使うのに必要なファイル一式がダウンロードされます。

$ bower install –save Polymer/polymer#^1.1.0

カスタム要素を定義したHTMLを作成する

Polymerのインストールが終わったら、カスタム要素を作成しましょう。カスタム要素の定義はHTMLファイルに記述します。 以下のような内容のmy-element.htmlを作成してください。これは<template>内に書かれたDOMをそのまま表示するだけの単純なカスタム要素です。要素名はmy-elementとしました。Web Componentsの決まり事により、カスタム要素の名前は必ずひとつ以上の’-’(ハイフン)を含まなければいけません。 my-element.html [html] <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="my-element"> <template> <p>This is my-element</p> </template> <script> Polymer({ is: "my-element" }); </script> </dom-module> [/html]

カスタム要素をインポートし、使用するHTMLを作成する

次に、カスタム要素を読み込んで使用するHTMLを作成しましょう。<head>内ではwebcomponents-lite.min.js(Web Componentsのpolyfillライブラリ)と先ほど作成したmy-element.htmlを読み込んでいます。 デモ [html] <!DOCTYPE html> <html> <head> <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> <link rel="import" href="my-element.html"> </head> <body> <my-element></my-element> </body> </html> [/html]

Polymerを使うとカスタム要素をシンプルに定義できる

本記事の冒頭で、Polymerは、Web Componentsをより使いやすくするために作られたと述べました。ここで一度、この点について、確認しましょう。 Polymerの大きな特徴の一つは、カスタム要素を宣言的に定義できることです。素のWeb Componentsによるカスタム要素の定義は命令的で、やや煩雑です。実際に、上述のmy-element.htmlで定義したのと同じものを素のWeb Componentsで書いた場合と比べてみます。 素のWeb Componentsの例 [html] <template id=’my-element-template’> <p>This is my-element</p> </template> <script> var MyElementPrototype = Object.create(HTMLElement.prototype); MyElementPrototype.createdCallback = function () { var shadowRoot = this.createShadowRoot(); var template = document.querySelector(‘#my-element-template’); var clone = document.importNode(template.content, true); shadowRoot.appendChild(clone); }; document.registerElement(‘my-element’, { prototype: MyElementPrototype }); </script> [/html] どうでしょうか?素のWeb Componentの方は、プログラムを書いているという印象が強いかと思います。Polymerを使った場合の方が、だいぶシンプルに感じられるでしょう。

Polymerのいろいろな機能を試す

さて、ここまでの例では、単純すぎて、Polymerを使ってどのようなことができるのか、あまり見えてこないかもしれません。ここからは、サンプルコードを少しずつ発展させていくかたちで、Polymerのいくつかの機能を紹介します。

スタイルを指定する

<dom-module>内でstyleを指定すると、<template>内に書かれたDOMにだけ、スタイルが適用されます。 例えば、カスタム要素を定義するstyle-example.htmlと、それを使用するstyle-demo.htmlをそれぞれ以下のような内容で作成してみましょう。 ブラウザで表示すると、このような見た目になります。 polymer-style-demo style-example.html [html] <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="style-example"> <template> <style> button { display: inline-block; padding: 6px 12px; font-size: 14px; line-height: 1.42857143; cursor: pointer; border: 1px solid transparent; border-radius: 4px; color: #333; background-color: #fff; border-color: #ccc; } button:hover{ color: #333; background-color: #e6e6e6; border-color: #adadad; } button:active{ border:1px solid #334c66; box-shadow:inset 0px 0px 2px #3a6da0; } </style> <button>Style Example</button> </template> <script> Polymer({ is: "style-example" }); </script> </dom-module> [/html]   style-demo.html [html] <html> <head> <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> <link rel="import" href="style-example.html"> </head> <body> <style-example></style-example> <button>Button</button> </body> </html> [/html] style-example.htmlの中に書いたスタイルは<style-example>にだけ反映され、その次の<button>には反映されていません。 このように、styleの適用範囲が制限されるため、カスタム要素はカプセル化された部品として扱いやすくなります。

content要素を使う

前の例ではmy-buttonに表示する文字は固定でしたが、<content>要素を使うことで、カスタム要素を呼び出す側から<template>内にテキストやDOMを挿入することができます。以下の例では、content-demo.html側でボタンの中に表示するテキストを指定しています。 デモ content-example.html [html] <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="content-example"> <template> <style> /*省略*/ </style> <button><content></content></button> </template> <script> Polymer({ is: "content-example" }); </script> </dom-module> [/html]   content-demo.html [html] <!DOCTYPE html> <html> <head> <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> <link rel="import" href="content-example.html"> </head> <body> <content-example>Click Me!</content-example> </body> </html> [/html]

マルチデバイスのイベントリスナーを使う

Polymerでは’tap’, ‘down’, ‘up’, ‘track’というGesture eventが用意されており、それらはPCのようなマウスを利用するデバイスでも、スマホやタブレットのようなタッチデバイスでもきちんとイベントが発生するようになっています。例えば、clickのかわりにtapを使うことが推奨されています。 イベントリスナーをセットアップするには、要素を宣言する際に、イベント名とイベントハンドラー名のマッピングを記述したlistnersオブジェクトを指定します。 また、イベント名をnodeId.eventNameのように指定することで、特定の要素に対してのイベントだけを指定することもできます。以下は、ボタンをクリック/タップした場合に、アラートダイアログを表示させる例です。 デモ event-listener-example.html [html] <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="event-listener-example"> <template> <style> /*省略*/ </style> <button><content></content></button> </template> <script> Polymer({ is: "event-listener-example", listeners : { ‘tap’ : ‘hello’ }, hello : function() { alert(‘Hello!’); } }); </script> </dom-module> [/html]

プロパティを宣言する

propertiesオブジェクトを指定することで、任意のプロパティを宣言することができます。また、プロパティの値はマークアップで指定することができます。 以下の例では、カスタム要素を宣言しているproperties-example.htmlの中で、messageというプロパティを宣言し、デフォルト値を’Hello’にしていますが、properties-demo.htmlでmessageの値を’Hi’としています。したがって、ボタンをクリックすると’Hi’と書かれたアラートダイアログが表示されます。 デモ properties-example.html [html] <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="properties-example"> <template> <style> /*省略*/ </style> <button><content></content></button> </template> <script> Polymer({ is: "properties-example", properties: { message: { type:String, value: ‘Hello’ } }, listeners: { ‘tap’: ‘hello’ }, hello: function() { alert(this.message); } }); </script> </dom-module> [/html]   properties-demo.html [html] <!DOCTYPE html> <html> <head> <script src="bower_components/webcomponentsjs/webcomponents-lite.min.js"></script> <link rel="import" href="properties-example.html"> </head> <body> <properties-example message="Hi">Click Me!</properties-example> </body> </html> [/html]

データバインディングを使う

Polymerはデータバインディング機能を提供しており、カスタム要素のプロパティを画面表示に反映させたり、UIからの入力をプロパティに反映させることができます。 以下は、双方向のデータバインディングの例で、テキストボックスのvalueの値をmessageプロパティに反映させ、また、messageプロパティが変更された際に、テキストボックスのvalueの値を変更します。 したがって、alertを呼び出すタイミングでは、messageの値はテキストフィールドに入力された文字列と同じですが、その後、messageの値を’Hello’に変更しているので、テキストフィールドに表示される値もHelloに戻ります。 デモ data-bind-example.html [html]</p> <link rel="import" href="bower_components/polymer/polymer.html"> <dom-module id="data-bind-example"> <template> <style> /*省略*/ </style> <input id="input" type="text" value="{{message::input}}"> <button id="button"><content></content></button> </template> <script> Polymer({ is: "data-bind-example", properties: { message: { type: String, value: "Hello", notify: true } }, listeners: { ‘button.tap’: ‘hello’ }, hello: function() { alert(this.message); this.message = ‘Hello’; } }); </script> </dom-module> <p class="crayon-selected">[/html] 双方向データバインディングを行うためにはいくつかポイントがあります。 ひとつ目は、プロパティ宣言時にnotify:trueを指定することです。これを指定しないと(デフォルトはnotify: false)、Javascriptでプロパティの値を変更した時に、テキストボックスのvalueの値は変更されません。 ふたつ目は、value=”{{message::input}}”という記法です。これは一般化すると、 対象プロパティ=”{{カスタム要素のプロパティ::イベント}}” となり、今回の例では、「inputイベントが生じたら、messageにvalueの値をセットする」ことを指定しています。

いくつかの補足とまとめ

すぐ使えるコンポーネント – Polymer Element Catalog

GoogleはPolymerライブラリだけでなく、Polymerで作られた様々なカスタム要素をPolymer Element Catalogで公開しています。 特に、Paper Elementsというカテゴリには、Googleが提唱するMaterial Designを実装した様々なコンポーネントが含まれています。是非活用しましょう。

Shadow DOMとShady DOMについて

本記事では、詳しく解説しませんが、Web Componentsの要素技術の一つに、コンポーネントのカプセル化を可能にするShadow DOMという仕組みがあります。 しかしながら、今のところ、Shadow DOMを実装しているブラウザは少ないです。 したがって、クロスプラットフォームで動作するために、ブラウザ間の実装の差を埋める必要があるのですが、完全なPolyfillの実現には、コードの肥大化、実行速度などの課題があります。 そこで、Polymer1.0では、ライブラリの軽量化と実行速度向上のために、Shadow DOMの完全なエミュレートを諦めて、Shady DOMと呼ばれる代替機能を用意しています。 そのため、厳密にはカプセル化が完全でないことや、DOM操作をするためには、Polymer独自のDOM APIを利用しなければならないなどの注意が必要です。 Shady DOMについての詳細はPolymerの公式サイトの記事”What is shady DOM”を参照してください。

PolymerでWeb Componentsをはじめよう

WebにおけるUIのコンポーネント化が標準化されるということは非常に大きなインパクトがあります。 したがって、Web Componentsに寄せられる期待は大きいと思います。 各ブラウザのネイティブでの実装については、まだ見通せないところがありますが、Polymerを使えば、今すぐに、クロスブラウザに対応したWeb Componentsを利用することができます。 自分でカスタム要素を作成するのは難易度が高いと思う人も、まずはPolymer Element Catalogで公開されているコンポーネントを使ってみることは簡単にできます。PolymerでWeb Componentsをはじめてみてはどうでしょうか。

Google のクラウドサービスについてもっと詳しく知りたい、直接話が聞いてみたいという方のために、クラウドエースでは無料相談会を実施しております。お申し込みは下記ボタンより承っておりますので、この機会にぜひ弊社をご利用いただければと思います。

無料相談会のお申込みはこちら