RiotはReactライクなマイクロMVPライブラリです。タスクランナーを噛ませたいので[こちらのサンプル](Adding compiled Riot tags to your Gulp + Browserify build)を動くようにしたり、いろいろいじってみた。
時計を表示するclock
タグを表示します。インスタンスごとに長針・短針・秒針の表示を変えています。マウスホバーでポーズします。
via Adding compiled Riot tags to your Gulp + Browserify build
Riotタグを書く
Riotの特徴はなんといってもHTML+CSS+JavaScriptの混ぜ書き。一見HTMLに見えますが、JavaScriptとしてトランスパイルされます。
<!-- clock.tag -->
<clock>
<svg>
<line></line>
<circle></circle>
...
</svg>
<style scoped>
:scope {
...
}
svg {
...
}
...
</style>
<script>
// ↑このscriptタグは省略できる
// ↓メソッド構文
test() {
...
}
// function文も共存する
function hogehoge() {
...
}
</script>
</clock>
シンタックスはとりあえず、スクリプト部分にscript
タグを入れてHTMLのシンタックスにしてみた。
scoped スタイル
scoped
スタイルはトランスパイルされるとそのタグの子セレクタとなります。
clock svg {
...
}
Firefoxだけはscoped
属性を実装しているようです。
メソッド構文
奇妙に見えますがRiotタグの中では
<clock>
test() {
...
}
</clock>
という書き方ができます。これはES6のクラス構文のような感じです。
class Clock {
test() {
...
}
}
同じタグの中にfunction
文による定義が混じっていると、一瞬あれっ、てなります。
トランスパイル後は
this.test = function() {
...
}.bind(this)
となります。この時のthis
はRiotタグのインスタンスになります。
メインで呼び出す
RiotとRiotタグをrequire
してmount
します。
// main.js
var riot = require('riot');
require('./tags/clock.tag');
riot.mount('clock');
GulpでRiotをトランスパイル
Riotタグのトランスパイルはriotifyが用意されています。あとはbaberifyと同様ですね。
//gulpfile.js
var gulp = require('gulp');
var browserify = require('browserify');
var riotify = require('riotify');
var source = require('vinyl-source-stream');
...
gulp.task('concat', function () {
return browserify({
debug: true,
entries: ['path/to/main']
}).transform([riotify])
.bundle()
.pipe(source('main.bundle.js'))
.pipe(gulp.dest('path/to/dest/'));
});
HTMLに組み込む
定義したタグとトランスパイルしたバンドルをHTMLに追加します。
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<title>Riot Clock</title>
</head>
<body>
<clock></clock>
<script src="main.bundle.js"></script>
</body>
</html>
ループ&子タグ
設定を配列で用意して子タグにオプションを渡す構造にしてみた。まず、親タグを書く。
<!-- clocks.tag -->
<clocks>
<clock
each={ clocks // means this.clocks }
some-opts={ someOpts // means this.clocks[*].someOpts }
another-opts={ anotherOpts // means this.clocks[*].anotherOpts }
...
></clock>
<script>
this.clocks = [{
// this child has no options
}, {
// this child has options
someOpts: true
}, {
// this child has another options
anotherOpts: true
},
// ...
}];
</script>
</clocks>
他のデータバインドやテンプレート言語の経験から
<!-- Didn't work -->
<clocks each={ clocks }>
<clock some-opts={ someOpts }></clock>
</clocks>
こう書きたくなりますが、違うみたいです。一方で、設定オブジェクトのプロパティをそのまま受け継いでおり、楽チンです。
メインでは両方のタグをマウントすればよし。
var riot = require('riot');
require('./tags/clocks.tag');
require('./tags/clock.tag');
riot.mount('*');
HTMLには親タグのみ記述
<clocks></clocks>
<script src="main.bundle.js"></script>
その他
モジュール化
タグ内部で普通にrequire
を使えるので、今までBrowserify等使っていれば、同じ感覚でコーディングできます。
<!-- clock.tag -->
<clock>
...
<script>
var $ = require('jquery');
...
</script>
</clock>
いろいろ外部化したほうが見やすいような気がします。Min-inのinit
メソッドは自動で実行されます。
// mixin/clock.js
var ClockMixin = {
init: function() {
...
},
test: function() {
...
}
}
module.exports = ClockMixin;
<!-- clock.tag -->
<clock>
...
<script>
var ClockMixin = require('path/to/mixin');
this.mixin(ClockMixin);
</script>
</clock>
ファイルが別になってしまうと、コンポーネントっぽさが失われてしまうというのはありますね。こうとか?
<!-- clock.tag -->
<clock>
...
<script>
...
this.mixin({
init: function() {
...
},
test: function() {
...
}
});
</script>
</clock>
Mix-inはRiot的には、このように書くようです。これはまたシンタックスががが…
<!-- clock.tag -->
var ClockMixin = {
init: function() {
...
},
test: function() {
...
}
}
<clock>
...
<script>
...
this.mixin(ClockMixin);
</script>
</clock>
使い方は簡単ですが、シンタックスとか記法に納得するのが大変かも。でも個人的には使ってみたいです。