Custom Elementを定義するには、Polymer.Elementの拡張クラスを作成し、そのクラスをcustomElements.defineメソッドに渡します。

仕様では、Custom Element名は、小文字のASCII文字で始まり、ダッシュ(-)を含まなければなりません。

例:

// define the element's class element
class MyElement extends Polymer.Element {

  // Element class can define custom element reactions
  connectedCallback() {
    super.connectedCallback();
    console.log('my-element created!');
  }

  ready() {
    super.ready();
    this.textContent = 'I\'m a custom element!';
  }
}

// Associate the new class with an element name
customElements.define('my-element', MyElement);

// create an instance with createElement:
var el1 = document.createElement('my-element');

// ... or with the constructor:
var el2 = new MyElement();

上記の通り、Custom Elementのライフサイクルで説明したようにエレメントのクラスにはCustom Elementのリアクションとしてコールバックを定義することができます。

ES6ではネイティブに提供されるサブクラス化の仕組みを活用することで、ES6の構文を使って定義済みの既存のエレメントを拡張したりカスタマイズしたりすることができます。:

// Subclass existing element
class MyElementSubclass extends MyElement {
  static get is() { return 'my-element-subclass'; }
  static get properties() { ... }
  constructor() {
    super();
    ...
  }
  ...
}

// Register custom element definition using standard platform API
customElements.define(MyElementSubclass.is, MyElementSubclass);

エレメントの拡張についての詳細は、Custom Elementのコンセプトの解説のセクションの他のエレメントの拡張を参照してください。

サブクラスにテンプレートを指定しない場合、デフォルトでスーパークラスのテンプレートが継承されます。この動作をオーバーライドしたり、スーパークラスのテンプレートを変更したりするには、サブクラスのtemplateのgetterメソッドをオーバーライドします。

ミックスイン によってコードをエレメント間で共有することができます。ミックスインを使い、トップの基底クラスに新たな機能を追加してみます。:

class MyElementWithMixin extends MyMixin(Polymer.Element) {

}

この例に関しては、2つのステップに分けて考えると理解しやすいでしょう。:

// Create a new base class that adds MyMixin's features to Polymer.Element
const BaseClassWithMixin = MyMixin(Polymer.Element);

// Extend the new base class
class MyElementWithMixin extends BaseClassWithMixin { ... }

ミックスインは単に継承チェーンにクラスを追加するだけなので、継承の一般的なルールがそのまま適用されます。

ミックスインの定義に関する詳細は、Custom Elementのコンセプトのクラス式のミックスインでコードを共有を参照してください。

Polymer Elementを定義するのに三つの主要なHTML Importsがあります。:

インポート 説明
polymer-element.html Polymer.Elementを基底クラスに定義します。
legacy-element.html Polymer.Elementを拡張し、Poymer 1.xと互換性のあるPolymer.LegacyElementAPIが付加されたPolymer.LegacyElementを基底クラスにエレメントを定義します。また、レガシーなファクトリメソッドPolymer()を利用して、1.xと2.xのハイブリッドエレメントを定義することもできます(polymer-element.htmlを含んでいます)。
polymer.html 1.xでpolymer.htmlのバンドルに含まれていたヘルパーエレメント(custom-styledom-binddom-ifdom-repeatなど)を加えてインクルードします(legacy-element.htmlを含んでいます)。

リソースを最小限にしたい場合には、polymer-element.htmlをインポートし、必要なヘルパーエレメントを個別にインポートして下さい。

1.xの後方互換APIが必要な場合には、2.xのクラススタイルのエレメントを作成する際の基底クラスとしてPolymer.LegacyElementを使用できます。またヘルパーエレメントを利用する場合は個別にインポートする必要があります。

1.xと2.xの両方で動作可能なハイブリッドエレメントを定義するには、polymer.htmlをインポートして使用します。

Polymer.mixinBehavior関数を使用して、クラススタイルのエレメントにハイブリッドな動作(behavior)を付加することができます。:

class XClass extends Polymer.mixinBehaviors([MyBehavior, MyBehavior2], Polymer.Element) {

  ...
}
customElements.define('x-class', XClass);

このmixinBehavior関数は、1.xのレガシーAPIもミックスインするので、Polymer.LegacyElementを拡張したのとほとんど同じことです。これらのレガシーAPIが必要とされるのは、ハイブリッドな動作(behavior)がそれらに依存しているためです。

試験的な実装においては、メインドキュメントからエレメントを定義するだけで済むかもしれません。本番環境では、常にエレメントは分割したファイルに定義した上で、メインドキュメントにインポートする必要があります。

メインのHTMLドキュメントでエレメントを定義するには、エレメントはHTMLImports.whenReady(callback)から定義します。callbackはドキュメント内の全てのインポートの読み込み(loading)が完了した時点で呼び出されます。

<!DOCTYPE html>
<html>
  <head>
    <script src="bower_components/webcomponentsjs/webcomponents-lite.js">
    </script>
    <link rel="import" href="bower_components/polymer/polymer-element.html">
    <title>Defining a Polymer Element from the Main Document</title>
  </head>
  <body>
    <dom-module id="main-document-element">
      <template>
        <p>
          Hi! I'm a Polymer element that was defined in the
          main document!
        </p>
      </template>
      <script>
        HTMLImports.whenReady(function() {
          class MainDocumentElement extends Polymer.Element {

            static get is() { return 'main-document-element'; }

          }
          window.customElements.define(MainDocumentElement.is, MainDocumentElement);
        });
      </script>
    </dom-module>
    <main-document-element></main-document-element>
  </body>
</html>

レガシーなエレメントは、エレメントの登録にPolymer関数が使用できます。関数は新しいエレメントのプロトタイプを引数に取ります。プロトタイプには、Custom ElementのHTMLタグ名を指定するisプロパティが必要です。

仕様では、Custom Elementの名前はASCII文字で始まり、ダッシュ(-)を含む必要があります。

例:

    // register an element
    MyElement = Polymer({

      is: 'my-element',

      // See below for lifecycle callbacks
      created: function() {
        this.textContent = 'My element!';
      }

    });

    // create an instance with createElement:
    var el1 = document.createElement('my-element');

    // ... or with the constructor:
    var el2 = new MyElement();

Polymer関数は、エレメントをブラウザに登録し、コードからエレメントインスタンスを新規に生成するコンストラクタを返します。

Polymer関数はCustom Elementのプロトタイプチェーンを構築し、それをPolymerのBaseプロトタイプ(Polymerの付加的な機能を提供)につなぎます。そのため開発者が独自のプロトタイプチェーンを構築することはできません。しかし、behaviorsプロパティを使用することでエレメント間でコードを共有することはできます。

Polymer.Elementクラスは、Polymerのビルトイン機能で必須のタスクを実行するため、Web標準のCustom Elementのライフサイクルコールバックを実装しています。

また、Polymerは、エレメントのDOMの生成と初期化が完了した時点で呼び出されれるreadyという特別なコールバックも用意しています。

レガシーコールバック 説明
created エレメントの生成後、プロパティ値の設定やローカルDOMの初期化前に呼び出されます。

プロパティ値が設定される前のワンタイムの初期化に利用されます。

ネイティブのconstructorに相当します。

ready プロパティ値が設定され、ローカルDOMが初期化された後に呼び出されます。

ローカルDOMの初期化後に、コンポーネントのワンタイムな設定を行うのに利用されます。(プロパティ値を元に設定する場合は、オブザーバーを利用した方が良いかもしれません)。

attached エレメントがドキュメントに追加(attached)された後に呼び出されます。エレメントの存続期間中であれば複数回呼び出すことができます。初回のattachedコールバックはreadyコールバックが実行されるまで呼び出されないことが保証されています。

ドキュメントレベル(document-level)のイベントリスナーを追加するのにも利用されます。(エレメントに対してローカルなイベントリスナーを設定するには、アノテーション付イベントリスナーリスナーオブジェクトのような宣言的なイベント処理を利用できます)。

ネイティブのconnectedCallbackに相当します。

detached エレメントがドキュメントから切り離された(detached)された後に呼び出されます。エレメントの存続期間中であれば複数回呼び出すことができます。

attachedコールバックで追加されたイベントリスナーの削除にも利用されます。

ネイティブのdisconnectedCallbackに相当します。

attributeChanged エレメントの属性の一つが変更されたときに呼び出されます。

対応するプロパティが宣言されていない属性の変更を扱う場合に利用できます。(対応するプロパティが宣言されている場合は、属性のデシリアライゼーションで説明しているように、Polymerが自動的に属性の変更を処理します)。

ネイティブのattributeChangedCallback相当します。

レガシーなエレメントにおいてはbehaviorsフォームを利用することでエレメント間でコードを共有することができます。behaviorにはプロパティ、ライフサイクルコールバック、イベントリスナーやその他の機能を定義することができます。

より詳細なガイドは、Polymer 1.xのドキュメントのBehaviorsのセクションを参照してください。