これぐらいでイイ これぐらいがイイ Riot.js

f:id:Naotsugu:20160613235604p:plain


Riot.js(ライオット) とは

React と Polymer のコンセプトをすごくシンプルに体現したUIライブラリです(Riot 2.0)。

公式サイトでは大きく以下が挙げられています。

  • CUSTOM TAGS
  • ENJOYABLE SYNTAX
  • VIRTUAL DOM
  • TINY SIZE

しかし、一番のポイントは、「Small learning curve」 ではないでしょうか。

公式サイトの短いガイドをななめ読みしただけで、それなりに使えてしまいます。 乱立するフロントエンドライブラリの中で、これほど学習曲線が小さなものってちょっと他に無い気がします。

簡単なサンプル

お気に入りのテキストエディタで example.html を作成します。

<!DOCTYPE html>
<html>
<head>
    <title>Riot</title>
</head>
<body>

    <hello/>

    <script type="riot/tag" src="hello.tag"></script>
    <script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
    <script>riot.mount('hello')</script>

</body>
</html>

Riot のカスタムタグ hello.tag を作成します。

<hello>
    <h3>{ message }</h3>

    <style scoped>
        h3 { font-size: 14px; }
    </style>

    <script>
        this.message = 'Hello Riot'
    </script>

</hello>

ブラウザで表示してみましょう。

f:id:Naotsugu:20160614003125p:plain

hello というタグを作成して riot.mount('hello') でマウントするだけです。

React が JavaScript の中に JSX という形で HTML を扱うのに対して、Riot ではタグHTMLの中にスクリプトを書きます。 example.html の中で作成したタグを使えるようになります。

マウント

riot.mount(customTagSelector, [opts]) ページ上のすべてのカスタムタグをマウントする場合は * でマウントします。

<script>riot.mount('*')</script>


引数を付けると、

<hello/>
<script>riot.mount('hello', {message: 'Hello Riot!!'})</script>

opts から参照できます。

<hello>
    <p>{ opts.message }</p>
</hello>

タグのインスタンスには以下のプロパティが設定されます。

  • opts - タグに渡されたオプション
  • parent - 親タグ (もしあれば)
  • root - ルートになるDOMノード
  • tags - 入れ子になっているカスタムタグ

ループ

ループは each 属性を使います。

<ul>
    <li each={ items }>{ title }</li>
</ul>

<script>
this.items = [
    { title: 'First item', done: true },
    { title: 'Second item' },
    { title: 'Third item' }
]
</script>

Conditional

Conditional 属性で要素の表示/非表示を制御できます。

<div if = { error }>
<div show = { error }>
<div hide = { error }>
  • show 真のときに、style="display: ''"として要素を表示
  • hide 真のときに、style="display: none"として要素を非表示
  • if ドキュメントの要素を、追加(真のとき)あるいは削除(偽のとき)

expressions

カーリーブレスでテンプレートに変数を挿入できます。

{ value }
{ title || '名称未設定' }
{ results ? '準備OK!' : '読み込み中...' }
{ new Date() }
{ message.length > 140 && 'メッセージが長すぎます' }

真偽値属性 (checked, selected など) はテンプレート変数が falsy であれば無視されます。

<input checked={ null }>

class にはショートカットが書け、以下の例は<p class="selected"}> のように評価されます。

<p class={ selected: true, bar: 0 }>

イベント

「on」で始まる属性(onclick、onsubmit、oninputなど)には、イベントにより呼ばれる関数を設定できます。

<button onclick={ go }>

this.go = function (e) { ... }
  • e.currentTarget イベントハンドラが指定された要素
  • e.target イベントの送信元エレメント
  • e.which キーボードイベント(keypress、keyupなど)のキーコート
  • e.item ループの中でのみ有効な、現在の要素

Named elements

name または id 属性のある要素は、自動的にコンテキストに追加され、this 経由でアクセスできます。

<login>
  <form id="login" onsubmit={ submit }>
    <input name="username">
    <input name="password">
    <button name="submit">
  </form>

  var form = this.login,
    username = this.username.value,
    password = this.password.value,
    button = this.submit
</login>

タグのネスト

tags 変数からネストしたタグにアクセスできます。

<my-tag>
  <child></child>
  var child = this.tags.child
</my-tag>

<child>
  ・・・
</child>

子タグは親タグの中で宣言れば riot.mount しなくても使えます。

<child name='my_nested_tag'></child> のように名前を付けてアクセスすることもできます。

update

タグの明示的な更新は update を使います。

this.update()

非UIイベントやAJAX呼び出しの場合には明示的に更新を行う必要があります。 通常は自動的に更新されます。

以下の記載は、

self.error = error_message
self.update()

以下と同じ意味になります。

self.update({ error: error_message })

ページの全てのタグを更新するには riot.update() を使います。

unmount

マウントの解除は unmount を使います。

this.unmount()
this.unmount(true) // 子タグをアンマウントし、親タグを残す

yield

以下のような my-post.tag を定義して、

<my-post>
  <h1>{ opts.title }</h1>
  <yield/>
  this.id = 666
</my-post>

呼び出し元のHTMLで以下のようにすると、

<my-post title="What a great title">
  <p id="my-content-{ id }">Foo</p>
</my-post>

<yield/> の箇所に <p id="my-content-666">Foo</p> が展開された結果となります。


post.tag を以下のようにして、

<post>
  <yield from='title'/>
  <yield from='body'/>
</post>

呼び出し元のHTMLで以下のようにすると、

<post>
  <yield to='title'>Hello</yield>
  <yield to='body'>Hey there world</yield>
</post>

タグ内のそれぞれの箇所に展開できます。

Observable

イベントの監視は observable にて行います。

イベントに応答するコードを on にて定義します。

var bus = riot.observable();

bus.on('myEvent', function(data) {
  // your code here
});

イベントのトリガは trigger にて行います。

bus.trigger('myEvent', { price: 11 });


Car オブジェクトを監視対象にして、

function Car() {
  riot.observable(this)
  this.on('start', function() {
    // engine started
  })
}

Car オブジェクトに対してtrigger のように使うこともできます。

var car = new Car()
car.trigger('start')

Router

URL の変更時にコールバックするには、riot.route(filter, callback) を使います。

// `/fruit/apple`
riot.route('/fruit/*', function(name) {
  console.log('The detail of ' + name)
})

// `/blog/2015-09/01` -> '2015', '09' '01'
riot.route('/blog/*-*/*', function(year, month, date) {
  console.log('The page of ' + year + '-' + month + '-' date)
})

フィルタには * でURLにマッチできます。

以下のようにクエリを取得することもできます。

// `/search?keyword=Apple`
riot.route('/search..', function() {
  var q = riot.route.query()
  console.log('Search keyword: ' + q.keyword)
})

riot.route('/search?keyword=*', function(keyword) {
  console.log('Search keyword: ' + keyword)
})


ブラウザのURLを変えるには以下のようにします。

riot.route('customers/267393/edit')

引数でタイトルを渡すこともできます。

riot.route('customers/267393/edit', 'Editing customer page')


URLの監視はstart にて開始できます。

riot.route.start()

まとめ

以上簡単ですが、Riot.js (現在のバージョンは 2.4.1) の使い方をみてみました。

API も少なく非常に簡単ですので、公式サイト を一通り目を通してみてはいかがでしょうか。




開眼!  JavaScript ―言語仕様から学ぶJavaScriptの本質

開眼! JavaScript ―言語仕様から学ぶJavaScriptの本質

  • 作者:Cody Lindley
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2013/06/19
  • メディア: 単行本(ソフトカバー)