手抜きタイトルのはじめてシリーズ3つ目。近頃、耳にすることの多いRiot.jsをさわってみました。
Riot.jsとは
Riot.js — A React-like user interface micro-library(日本語訳)
- Reactを意識して作られた超軽量のUIライブラリ、ビュー部分(コンポーネント)に特化
- Web componentsのように利用できる
- HTMLの中に、JavaScriptやCSSを書く
- 軽量、5.7KB
- インブラウザ・コンパイルを利用することで、CDNを読み込むだけで手軽に利用できる
- 開発元:MUUT
簡単な利用例
今回試した内容のリポジトリ。
以下手順で利用可能。
- CDNの読み込み
- コンポーネントの定義と読み込み
- コンポーネントのマウント
/01/index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>一番かんたんなRiot.js</title>
<!-- include riot.js -->
<script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
</head>
<body>
<h1>一番かんたんなRiot.js</h1>
<!-- place the custom tag anywhere inside the body -->
<sample></sample>
<!-- include the tag -->
<script type="riot/tag" src="sample.tag"></script>
<!-- mount the tag -->
<script>
riot.mount('sample', {
who: 'Riot'
})
</script>
</body>
</html>
インブラウザ・コンパイルをする場合は、riot+compiler.min.jsを読み込む。
コンポーネントの定義
/01/sample.tag
<sample>
<h3>{ message }, {opts.who} !</h3>
<ul>
<li each={ techs }>{ name }</li>
</ul>
<script>
this.message = 'Hello';
this.techs = [
{ name: 'HTML' },
{ name: 'JavaScript' },
{ name: 'CSS' }
]
</script>
<style scoped>
:scope { font-size: 2rem }
h3 { color: #0055aa }
ul { color: #ff5577 }
</style>
</sample>
上記でh3やulのstyleを変更してるが、styleタグにscopedを指定してるため、コンポーネント外には適用されない。(Web componentsやAngular2と同じ感じ)
セミコロンを省略してるのは意図的らしい。(書いても問題なし)
こうなる
scriptタグの省略
- scriptタグの記述は省略できる。
- エディタの対応を考慮してscriptタグを記述してもよいようになっている。
- 逆にコンポーネントをhtmlファイル内に直書きする場合は、scriptタグが入れ子になってしまうので省略する必要がある。(以下参照)
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>HTML内でコンポーネントを定義する</title>
<!-- include riot.js -->
<script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
</head>
<body>
<h1>HTML内でコンポーネントを定義する</h1>
<sample></sample>
<script type="riot/tag">
<sample>
<h3>{ message }, {opts.who} !</h3>
<ul>
<li each={ techs }>{ name }</li>
</ul>
<style scoped>
:scope { font-size: 2rem }
h3 { color: #0055aa }
ul { color: #ff5577 }
</style>
this.message = 'Hello'
this.techs = [
{ name: 'HTML' },
{ name: 'JavaScript' },
{ name: 'CSS' }
]
</sample>
</script>
<script>
riot.mount('sample', {
who: 'Riot'
})
</script>
</body>
</html>
疑問点
- li内でプレフィックスなしでいきなり { name } とか書いてるけど、入れ子の場合とかでnameの所在オブジェクトを明示したい時とかどうするんだろう。
scriptで利用できるプリプロセッサ
type属性に以下の指定が使用できる。
- es6
- babel
- coffee
- livescript
- typescript
- vanilla
これらを利用する場合は、riot コマンドによるプリコンパイルが必要なので、riotをグローバルにインストールする必要あり。
sudo npm i -g riot
riot --help
ES2015で書いてみる
/03/index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>babel+es6で書いてみる</title>
<!-- プリコンパイルしてるのでriot.jsのみの読み込みでOK -->
<!--<script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>-->
<script src="//cdn.jsdelivr.net/riot/2.4/riot.min.js"></script>
</head>
<body>
<h1>babel+es6で書いてみる</h1>
<es6test></es6test>
<!-- babelでプリコンパイルしたjsファイルを読む -->
<script src="es6test.js"></script>
<script>
riot.mount('*');
</script>
</body>
</html>
プリコンパイルするのでriot.min.jsのみを読み込めばOK.
/03/es6test.tag
<es6test>
<h3>{ test }</h3>
var type = 'ES2015'
this.test = `This is ${type}`
</es6test>
コンパイルするにはグローバルにbabelをインストールする必要があるっぽい
sudo npm i -g babel
コンパイル。
riot 03/es6test.tag
出力先を指定する場合は以下のようにする。
riot 03/es6test.tag dist
これで03/es6test.jsが生成され、以下のよう表示される。
ソースの変更を監視するには -w を指定する
riot -w src dist
gulpやbrowserifyやwebpackへの組み込無場合は以下参照。
- e-jigsaw/gulp-riot: gulp plugin for riot
- jhthorsen/riotify: browserify plugin for riot tag files
- esnunes/riotjs-loader: riotjs module loader for webpack
htmlやcssは...
- htmlにテンプレートエンジンのpug/jadeが利用できる
- cssにlessが利用できる
<script type="riot/tag">
...
<style type='less'>
</style>
</sctipt>
お手軽ルーター
ルーターをお手軽に利用できる。
/04/index.html
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>お手軽ルーター</title>
<style>
body{
margin: 0 16px;
}
</style>
<script src="https://cdn.jsdelivr.net/riot/2.4/riot+compiler.min.js"></script>
</head>
<body>
<app></app>
<script type="riot/tag">
<app title="hoge">
<style scoped>
ul{
margin: 0 -16px;
background-color: #000;
}
li{
padding: 8px 16px;
list-style: none;
display: inline-block;
}
a:visited,
a{
color: #fff;
}
</style>
<ul>
<li><a href='#home'>home</a></li>
<li><a href='#blog'>blog</a></li>
<li><a href='#contact'>contact</a></li>
</ul>
<content></content>
riot.route(function(tagName) {
tagName = tagName || 'home';
riot.mount('content', tagName);
});
riot.route.start(true);
</app>
<home>
<h2>Home</h2>
<p>Lorem Ipsum is simply dummy text of the printing and typesetting industry. </p>
</home>
<blog>
<h2>blog</h2>
<p>It is a long established fact that a reader will be distracted by the readable content of a page when looking at its layout. </p>
</blog>
<contact>
<h2>contact</h2>
<p>Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words, consectetur, from a Lorem Ipsum passage, and going through the cites of the word in classical literature, discovered the undoubtable source. </p>
</contact>
</script>
<script>
riot.mount('*')
</script>
</body>
</html>
上記構成をシンプルに書くとこんな感じ。
<app></app>
<script type="riot/tag">
<app>
<a href='#home'>home</a>
<a href='#blog'>blog</a>
<a href='#contact'>contact</a>
<content></content>
riot.route(function(tagName) {
tagName = tagName || 'home';
riot.mount('content', tagName);
});
riot.route.start(true);
</app>
<home></home>
<blog></blog>
<contact></contact>
</script>
- riot.route(function(tagName){ ... で、hashchangeした時の処理を定義
- riot.mount(A, B) で、AにBの内容を割り当てる
- riot.route.start(true) で、hashchangeの監視開始
参考サイト
- Riot.js — A React-like user interface micro-library · Riot.js
- フロント界隈で一番イケてるのは AngularJS でも React でもなく Riot.js だという話 | phiary
- Riot.js 2.2 情報まとめ - Qiita
- Riot.js 2.0 を触ってみた — まだReactで消耗しているの? - Qiita
感想
Web components的な管理とかルーター機能が手軽に使えるインブラウザ・コンパイルはいいかも。 さくっと書きたい時に使いたい。