#daiizメモ

Scrapboxに夢中

Polymer 1.0 の Shady DOM を覗いた

Polymer 1.0 の勉強を始めてみようと思う。
最近触っていなかったから、ひとまず思い出すために古いバージョン(v0.5)のPolymerで書いたscrollHeaderPanelと、新バージョン(v1.0)のものを見比べてみた。

名称が変わっていた

バージョンが変わっても、ほぼ同じ挙動をするelementだが、名称が変更になっていた。

  • ~ v0.5: core-scroll-header-panel
  • v1.0 ~: paper-scroll-header-panel

paper-グループに入っていた。

要素を使ってみる

まずは、これまでのバージョンでの使用法。例として、miilClientのコードを参考に書くとこんな感じ。

<core-scroll-header-panel condenses>
      <core-toolbar class=tall>
          <img src="icon.png" style="width:40px; height:40px">
          <div class="bottom indent title">scrollHeader</div>
      </core-toolbar>

      <div id="contents">
           (略)
      </div>
</core-scroll-header-panel condenses>

いい感じ。scrollHeaderPanelの上段にcore-toolbarを配置し、この中にアイコンと、タイトルを表示している。 下段にはメインのdiv #contentsを置いている。


続いて新バージョンの方法で書いてみる。ここでは省略してしまったCSSやJSなどを含めたコードサンプルは、sandbox/Polymer/scrollHeader at master · daiiz/sandbox · GitHub に置いてあります。

<paper-scroll-header-panel condenses>
    <paper-toolbar class="tall">
        <img src="icon.png" style="width:40px; height:40px;">
        <div class="bottom indent title">scrollHeader</div>
    </paper-toolbar>

    <div id="contents">
        (略)
    </div>
</paper-scroll-header-panel>

見た目

スクリーンショットは、以下のようになる。上にスクロールするすると、ヘッダー部分がグインと狭くなって、メインのContents領域が目一杯広がって良い。

見た目では、どちらのバージョンでもほぼ同じだった。

裏側

Chrome Dev Toolでレンダリングの状態を見てみると大きな違いがあった。まずは、古い方:


v0.5

ここでの一番のポイントは、#shadow-rootがあること。shadow-rootのもとに含まれるDOMはShadow DOMと呼ばれ、ここは「影の世界」ということなので、グローバルな領域(通常のDOMの世界)からは参照できないようになっている。なので、

document.querySelector('#mainContainer');

を実行しても、確かにnullが返ってくる。 core-scroll-header-panelcore-toolbarが読み込まれると、これらはShadow DOMとしてdivなどを創り、この影の世界をブラウザが解釈してブラウザ画面に表示している。


続いて、新しい方を見てみる:


v1.0

これを見たときの最初の感想は「あれれ、丸見え」だった。#shadow-rootは無く、ブラウザに表示されているものはすべて通常のDOMとして描かれていた。こんな状態なので、もちろん

というふうにして要素を取得することもできる。これだとshadow-rootに隠されていたことに比べて、styleを当てたりすることが簡単になった。 でも、「不必要なことは見せない」「見なくて良い」というWeb Compositionsのメリットが失われてしまったよう感じる。

そこで、Shady DOM

Polymer 1.0 からは「Shady DOM」という新しい考え方が導入された。この技術により、まだShadow DOMをサポートしていないブラウザにおいても軽快に動作をWeb Componentを作れるようになるらしい。

先ほどの中身が丸見えになってしまっていたpaper-scroll-header-panelの例だが、これをShady DOM APIを下記のように使って覗いてみた。

Polymer.dom(scrollHeaderPanel).children;

これを実行すると、

のようになった。最後に得られたarrayOfNodesは、まさに最初の方の「要素を使ってみる」の節で書いた2つの要素が展開されたものである。

つまり、

var scrollHeaderPanel = document.querySelector('paper-scroll-header-panel');

としたときに、

  • scrollHeaderPanel.children とすれば、いま、ブラウザ上で見えているDOMの世界が素直に得られる。(見たままDOM)
  • Shady DOM APIを用いて Polymer.dom(scrollHeaderPanel).children としたときには、カプセル化された世界観のDOMが得られる。また、これで得られる要素は実際にブラウザに表示されているNodeである。

ということだろうか。


今のところ「新しいPolymerでは、見た目では嘘をつかず(影に隠さず)、代わりにブラウザで見えていない本当のカプセル化されたDOM構造を取得するAPIを用意した」と理解している。ものすごく分かりやすくなって良い方法だと思う。

参考