LoginSignup
5
5

More than 5 years have passed since last update.

DartでCustom Elements

Last updated at Posted at 2014-12-24

こんにちは、らこです。Web ComponentsのCustom Elementsでアレする話をします。

Polymer is large

Custom ElementsといえばPolymerみたいな風潮出来始めてますよね。Polymerはほんとうに良く出来てると思いますし、Polyfillに関しては言うこと無いと思います。ですが、本質的に自分が何を達成したいのか考えるとPolymerは大きすぎるような気がしました。

やりたいこと=HTMLの分割

Custom Elementsを使って何をしたいかというと私はHTMLを分割したいだけです。独自タグを目印に別のHTMLを注入できればそれで満足です。そこにPolymerは必要なくて、ただWeb Componentsのpolyfillがあればいいだけだと気づいたので自分で作ることにしました。

生のDartで実装する

というわけで、Custom ElementsとHTML Importsもどきを実装してみました。
エントリポイントはこちら

web/index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>custom_elements_dart</title>
  <script src="packages/web_components/webcomponents.min.js"></script>
</head>
<body>
  <sample-element>
  </sample-element>
  <script type="application/dart">
    import 'dart:html';
    import 'package:custom_elements_dart/sample_element.dart';

    void main() {
      document.registerElement("sample-element", SampleElement);
    }
  </script>
  <script src="packages/browser/dart.js"></script>
</body>
</html>

エントリポイントでやってるのは、sample-elementタグの登録だけです。

  document.registerElement(String tagName, Type htmlElementType);

を呼び出すことで、タグ名と、それに対応するHtmlElement型のクラスをバインドします。

lib/sample_element.html
<div>
  <h1 id="greeting"></h1>

  <p>This is sample element.</p>

  <input id="nameInput" type="text"/>
</div>

読み込まれるHTMLです。#greeting#nameInputを定義してます

lib/sample_element
library sample_element;

import "dart:html";
import 'dart:async';
import "package:mustache/mustache.dart" as mustache;

class SampleElement extends HtmlElement {

  SampleElement.created() :super.created(){    
    onInput.matches("#nameInput").listen((e) {
      var name = (e.matchingTarget as TextInputElement).value;
      _greet(name);
    });

    getTemplate().then((template) {
      appendHtml(template);
      _greet("World");
    });
  }

  String _template;

  Future<String> getTemplate() {
    if (_template != null) {
      return new Future.value(_template);
    }
    return HttpRequest.getString("packages/custom_elements_dart/sample_element.html")
    .then((v) => _template = v);
  }

  _greet(String name) {
    if (name == null) {
      name = "World";
    }
    var greeter = mustache.parse("Hello {{name}}!");
    var output = greeter.renderString(
      {
        "name": name
      });
    this.querySelector("#greeting").innerHtml = output;
  }
}

追加した<sample-element>の中身です。

  SampleElement.created() :super.created(){

    onInput.matches("#nameInput").listen((e) {
      var name = (e.matchingTarget as TextInputElement).value;
      _greet(name);
    });

    getTemplate().then((template) {
      appendHtml(template);
      _greet("World");
    });
  }

HtmlElement.created()HtmlElementクラスのコンストラクタで、継承する際に必ず実装しないといけません。まず#nameInput要素からonInputイベントを拾って、ビューを更新するリスナを登録してます。

次にテンプレートHTMLを読み込んで、自身にappendした後に最初のビュー更新をかけています。

  String _template;

  Future<String> getTemplate() {
    if (_template != null) {
      return new Future.value(_template);
    }
    return HttpRequest.getString("packages/custom_elements_dart/sample_element.html")
    .then((v) => _template = v);
  }

ここがHTML Importもどきの部分です。Getリクエストで非同期にテンプレートHTMLを取得します。取得後はキャッシュしています。今思うとこれstaticにしたほうがいいですね。

  _greet(String name) {
    if (name == null) {
      name = "World";
    }
    var greeter = mustache.parse("Hello {{name}}!");
    var output = greeter.renderString(
      {
        "name": name
      });
    this.querySelector("#greeting").innerHtml = output;
  }

ビュー更新部分です。あいさつのテンプレートをMustacheでパースして、与えたnameを食わせています。文字列が出来上がったら#greeting要素に流し込んでいます。

こんな感じ

テキストボックスの変更が反映されます。MV*っぽい動きです。

customelement.gif

Polymer無くてもこれくらいはできる

結局Polymerもやってることはこれの応用というか、Dartでできることしかやってないので、当然ですがこのくらいはできます。ライブラリに頼るのもいいですが、自分でやるのも楽しいです。

めちゃくちゃ簡単

見てもらってわかるようにDartの場合、HTML要素とクラスが1:1対応してるので、めちゃくちゃ簡単に、わかりやすくCustom Elements使えます。HtmlElementを継承したクラスをregisterElementするだけです。冗談みたいに簡単に使えるのでJSerの人もCustom Elementsで遊ぶためだけにDartやってほしいくらいです。


以上DartでCustom Elements作る方法でした。Polymerもいいけど自作もね。

いよいよ次で最後ですね。最終日も私です。よろしくお願いします。

5
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
5