[Aurelia] 未来志向JavaScriptフレームワーク Aurelia 入門 3 ページ作成


[aurelia] 未来志向JavaScriptフレームワーク Aurelia 入門 2 環境構築の続きです。

ページ作成

ページ作成という言葉に違和感を感じつつ、進めます。

Aureliaでは、UIはviewとview-modelのペアで構成されています。
viewはHTMLで書かれ、DOMにレンダリングされます。
view-modelはJavaScriptで書かれ、データと振る舞いをviewに渡します。
Aureliaのデータバインディングはこれら二者をリンクし、データが変更されるとviewやmodelに反映されることを許容します。

view-model

ES7の記法でview-modelを記載します。
ES7はBabelにより現在のブラウザで走らせることが出来るようになっています。
当然ES7を必ずしも使う必要はありませんので、ES5でも問題ありません。

src/app.js
export class Welcome{
  heading = 'Welcome to the Aurelia Navigation App!';
  firstName = 'John';
  lastName = 'Doe';

  get fullName(){
    return `${this.firstName} ${this.lastName}`;
  }

  welcome(){
    alert(`Welcome, ${this.fullName}!`);
  }
}
src/app.html
<template>
  <section>
    <h2>${heading}</h2>

    <form role="form" submit.delegate="welcome()">
      <div class="form-group">
        <label for="fn">First Name</label>
        <input type="text" value.bind="firstName" class="form-control" id="fn" placeholder="first name">
      </div>
      <div class="form-group">
        <label for="ln">Last Name</label>
        <input type="text" value.bind="lastName" class="form-control" id="ln" placeholder="last name">
      </div>
      <div class="form-group">
        <label>Full Name</label>
        <p class="help-block">${fullName}</p>
      </div>
      <button type="submit" class="btn btn-default">Submit</button>
    </form>
  </section>
</template>

まず、すべてのviewはタグに包含されています。
formのinputの部分に、value.bind="firstName" とあります。これは、inputの valueをview-modelのfirstName propertyにデータバインドしています。view-modelのpropertyに変更がはいるといつでも、inputのvalueは新しい値に更新され、input側の値に変更が入るといつでも、Aureliaは新しいvalueをview-modelにpushします。

${fullname}という記述は、view-model側からviewへone-wayのデータバインディングをしていて、値をstringに自動で変換しdocumentに挿入しています。

最後にform element自体では、 submit.delegate="welcome()"とありますが、これはイベントバインディングをしています。
これにより、event delegationとsubmit eventが結びつき、formがsubmitされる度にwelcome methodが呼ばれることになります。

Data Binding

Aureliaはユニークで強力なデータバインディングエンジンを持っていて、状況に応じて、各propertyでの変更を監視する最良の方法をピックアップするアダプティブな手法を使います。

.bindコマンドはデフォルトのバインディング方法を実行します。
デフォルトではmodelからviewへのone-way bindingで、form control以外に適用されます。
これは.one-way, .two-way, .one-timeコマンドを使うことでoverrideできます。

同様に、event delegationには.delegateが使用でき、ターゲットの要素をダイレクトに狙うには.triggerを使うこともできます。

確認

$ gulp watch

http://localhost:9000/ にブラウザでアクセスするとアプリが見れます。

Adding Navigation

まずapp.jsとapp.htmlをそれぞれwelcome.js, welcome.htmlにrenameします。

そして再度app.js, app.htmlを作成し、それぞれをlayout, master pageとして扱います。

src/app.js
import 'bootstrap';
import 'bootstrap/css/bootstrap.css!';

export class App {
  configureRouter(config, router){
    config.title = 'Aurelia';
    config.map([
      { route: ['','welcome'], name: 'welcome',  moduleId: './welcome',      nav: true, title:'Welcome' }
    ]);

    this.router = router;
  }
}

Routerを使いたいので、App Classを作りconfigureRouter callbackをもたせます。
documentのtitleが生成された際にtitleをセット出来ます。
routesについて見ると、どのrouteも以下のpropertyを持ちます。

property description
route This is a pattern which, when matched, will cause the router to navigate to this route. You can use static routes like above, but you can also use parameters like this: customer/:id. There's also support for wildcard routes and query string parameters. The route can be a single string pattern or an array of patterns.
name This is a name to use in code when generating URLs for the route.
moduleId This is a path relative to the current view-model which specifies the view/view-model pair you want to render for this route.
title You can optionally provide a title to be used in generating the document's title.
nav If this route should be included in the navigation model because you want to generate a UI with it, set this to true (or a number indicating order)

訳を書くのがめんどくさかったので、そのまま載せましたが、
とても直感的に使える印象です。

src/app.html
<template>
  <nav class="navbar navbar-default navbar-fixed-top" role="navigation">
    <div class="navbar-header">
      <a class="navbar-brand" href="#">
        <i class="fa fa-home"></i>
        <span>${router.title}</span>
      </a>
    </div>

    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li repeat.for="row of router.navigation" class="${row.isActive ? 'active' : ''}">
          <a href.bind="row.href">${row.title}</a>
        </li>
      </ul>

      <ul class="nav navbar-nav navbar-right">
        <li class="loader" if.bind="router.isNavigating">
          <i class="fa fa-spinner fa-spin fa-2x"></i>
        </li>
      </ul>
    </div>
  </nav>

  <div class="page-host">
    <router-view></router-view>
  </div>
</template>

説明や補足などは次回に。

次回: [Aurelia] 未来志向JavaScriptフレームワーク Aurelia 入門 4 httpクライアントを使ってflickr APIを叩く