Master PG

プログラムし続ける...

【Polymer 1.0】Behaviors


目次


Bihaviorの定義

Polymerでは、カスタムエレメントはBehaviorと呼ばれるコードモジュールを継承することができます。

Behaviorは、Polymerエレメントのプロトタイプと似ており、ライフサイクルコールバック宣言型プロパティ属性observer (observers)listenersを定義できます。

PolymerエレメントのプロトタイプがBehaviorを継承するするには、behaviors配列に対象のBehaviorを指定します:

Polymer({
  is: 'super-element',
  behaviors: [SuperBehavior]
});

ライフサイクルコールバックが呼び出される順番はbehaviors配列で指定した順になり、最後にPolymerエレメントのプロトタイプのライフサイクルコールバックが呼びだされます。

ライフサイクルコールバック以外の関数はPolymerエレメントのプロトタイプに結合されます。behaviors配列で指定したBehaviorの中で同じ名前の関数が複数存在する場合は、behaviors配列の最後に指定されたBehaviorが優先されます。

新しく作成するBehaviorの名前ですが、今後Polymerが提供するBehaviorの名前と衝突するかもしれません。そこでBehaviorは特定の名前空間を使用するようにしてください:

MyBehaviors = MyBehaviors || {};
MyBehaviors.HighlightBehavior = { ... };


次のサンプルでは、ラベル部分をタップするとラベルのハイライト有り/無しがトグルします。<my-element>HighlightBehaviorを継承しており、振る舞い (ラベルタップ時の処理や、ラベルのCSSクラス切り替え等) はHighlightBehaviorが実装しています。<my-element>で行っていることはビューの定義のみです (Note: ライフサイクルコールバックの実行順を確認するためにビュー以外にもcreate()を実装はしています)。

⇒ ソースコード

Behaviorの定義:

<script>
  HighlightBehavior = {
    properties: {
      isHighlighted: {
        type: Boolean,
        value: false,
        notify: true,
        observer: '_highlightChanged'
      }
    },
    listeners: {
      tap: '_toggleHighlight'
    },
    created: function () {
      console.log('created: HighlightBehavior');
    },
    _toggleHighlight: function () {
      this.isHighlighted = !this.isHighlighted;
    },
    _highlightChanged: function (value) {
      this.toggleClass('highlighted', value);
    }
  };
</script>

Behaviorを継承するエレメントの定義:

<dom-module id="my-element">
  <template>
    <style>
      :host.highlighted {
        color: red;
        font-weight: bold;
      }
    </style>
    <div>Toggle Highlight</div>
  </template>
  <script>
    Polymer({
      is: 'my-element',
      behaviors: [HighlightBehavior],
      created: function () {
        console.log('created: my-element');
      }
    });
  </script>
</dom-module>

f:id:masterpg:20160923111839p:plain


Bihaviorの継承

既存のBehaviorを継承して新しいBehaviorを作成することができます。新しく作成するBehaviorは、Behaviorの配列として定義します:

<script>
  // 既存のBehavior
  OldBehavior = {
    properties: {
      elementName: String
    },
    say: function (message) {
      console.log(this.elementName + ': ' + message);
    }
  };
  
  // 新しく作成するBehaviorの実装
  NewBehaviorImpl = {
    // スーパクラス(OldBehavior)のsay()をオーバーライドしている
    say: function (message) {
      // スーパクラスのsay()を呼び出し、コンソールにメッセージを出力する。
      OldBehavior.say.call(this, message);
      // 自クラスの新しい機能としてポップアップでメッセージを表示する。
      // この際スーパクラスの`elementName`プロパティに`this`でアクセスしている。
      alert(this.elementName + ': ' + message);
    }
  };
  
  // 新しく作成するBehaviorの定義
  NewBehavior = [OldBehavior, NewBehaviorImpl];
</script>

既存のBehaviorを継承して新しいBehaviorを作成するには「実装」と「定義」を分けるのがよいでしょう。理由として、「定義」であるNewBehaviorに既存のOldBehaviorを指定することによって、「実装」のNewBehaviorImplOldBehaviorの機能を利用しながら新しいBehaviorを実装することができるためです。

「定義」であるNewBehaviorは、behaviors配列のように最も右のBihaviorが他のBihaviorより優先されます。この例ではNewBehaviorImplで定義されたもの全てがOldBehaviorより優先されます。


次のサンプルでは、上記のNewBehaviorを継承したエレメントを作成します。Tap Me!ボタンをタップするとポップアップメッセージと、コンソールにメッセージが出力されます。

⇒ ソースコード

<dom-module id="my-element">
  <template>
    <button on-tap="_buttonOnTap">Tap Me!</button>
  </template>
  <script>
    document.addEventListener('WebComponentsReady', function () {
      Polymer({
        is: 'my-element',
        behaviors: [NewBehavior],
        _buttonOnTap: function (event) {
          this.elementName = 'my-element';
          this.say('Hello World!');
        }
      });
    });
  </script>
</dom-module>

f:id:masterpg:20160923111913p:plain