今回はRito.jsのテンプレート(HTML)部分で用いる各種文法の紹介です。
ちょっと今回はボリューミーです。
変数の代入
まず、大原則として各種文法は {}
という波括弧を用いて定義していきます。
<sample>
<h1>{title}</h1>
<script>
this.title = 'Riot.js入門';
</script>
</sample>
ロジック部分で this
にインスタンスプロパティとして定義した値を、テンプレート部分で {変数名}
として代入することができます。
※ 注意:代入時には this
が省略される
グローバル変数の代入
Riot.jsのテンプレートエンジンは {変数名}
と定義した場合 this.変数名
をまず参照しようとし、もし値が undefined だった場合 window.変数名
を参照します。
なので、例えば常にフルスクリーンに表示したい要素を定義したいときは
<div style="width: {innerWidth}px; height: {innerHeight}px;"></div>
と書くと、まず this.innerWidth
を参照しようとし、その後に window.innerWidth
を参照するので、ブラウザのサイズが代入されるという流れになります。
アトリビュートの更新
{}
の中はJavascriptの文法がそのまま動いてくれます(ただし、1行分のみ。複数行のjsは書けない)。
なので、例えばclassの追加・削除を三項演算子を使って制御することもできます。
<sample>
<!-- isComplete がtrueならis-completeというクラスが追加されるが、falseなら空文字 = なにも追加されない -->
<div class="{isComplete ? 'is-complete' : ''}">やること</div>
<script>
this.isComplete = Math.random() > 0.5;;
</script>
</sample>
加えてRiot.jsでは、より簡潔にclassの追加・削除を行う仕様が用意されております。
<sample>
<div class={
'class-a': true,
'class-b': false,
'class-c': false,
'class-d': true
}>やること</div>
</sample>
このようにclassにクラス名をkey、真偽値をvalueにしたオブジェクトを渡すと、valueがtrueのクラス名だけ適応するということができます(この場合はclass-aとclass-dが適応されます)。
繰り返し処理:each
<sample>
<ul>
<li each={list}>{date}:{title}</li>
</ul>
<script>
this.list = [
{date: '2016/09/29', title: '木曜日'},
{date: '2016/09/30', title: '金曜日'}
];
</script>
</sample>
繰り返しで定義したいタグに対し、each
アトリビュートを付け、配列、またはオブジェクトを渡します。
配列でのeach
<sample>
<ul>
<li each={name in list}>{name}</li>
</ul>
<script>
this.list = ['taro', 'jiro', 'saburo'];
</script>
</sample>
配列の場合は each
と合わせて in
という文法を用います。
この場合の name
の部分は自由に変えて大丈夫です。
index or keyの取得
<sample>
<ul>
<!-- 1位:taro 2位:jiro 3位:saburo と出力される -->
<li each={name, i in list}>{i + 1}位:{name}</li>
</ul>
<script>
this.list = ['taro', 'jiro', 'saburo'];
</script>
</sample>
配列ならindex番号、オブジェクトならkeyに当たる部分も in
を使うことで取得できます。
条件分岐:if
<sample>
<div if={isShowed}>見えない</div>
<script>
this.isShowed = false;
</script>
</sample>
if
アトリビュートに値を渡すと真偽値として評価され、trueだったらレンダリング、falseだったらDOMツリーから削除されます。
※ 注意:else
とかはありません
イベントハンドラーの定義:on~
<sample>
<div ontouchstart={handleTouchStart} ontouchmove={handleTouchMove} ontouchend={handleTouchEnd} ontouchcancel={handleTouchEnd}>タッチしてね</div>
<script>
handleTouchStart() {
// something to do
}
handleTouchMove() {
// something to do
}
handleTouchEnd() {
// something to do
}
</script>
</sample>
このようにアトリビュートに on~
とイベント名を与え、コールバック関数を定義することで addEventListener
と同様のことができます。
※ 注意:アトリビュート名はすべてキャメルケース(onClick)でなくロワーケース(onclick)で書く
インスタンスメソッドの定義
Riot.jsにはインスタンスメソッドの定義の仕方が2つあります。
handleTouchStart() {
// something to do
}
this.handleTouchStart = function() {
// something to do
}.bind(this);
上はRiot.jsが es2015
風に定義できるように用意してくれた書き方で、下は最終的にコンパイルされる形です。
上の書き方の方がシンプルで簡潔ですが、使用するエディタによっては正しく文法チェックなどができない場合はあるので、その場合は下の書き方にしましょう。
※ 注意:下の書き方の場合 bind(this)
を忘れずに
on~アトリビュートを使うメリット
addEventListener
でなく on~
アトリビュートを使うメリットとして、add~
で定義した場合は、イベントが不要になった場合、自分で removeEventListener
を呼ばなくてはいけません。
しかし on~
の場合、コンポーネントがマウント(DOMツリーに追加)されたタイミングで自動で付与し、アンマウント(DOMツリーから削除)されたタイミングで自動で削除してくれます。
これによって、イベントの消し忘れや、再度マウントした時の二重掛けを防止できます。
また、次回紹介する テンプレートを更新される update
という仕組み も、on~
で与えたイベントが発火したタイミングで自動で実行してくれます。
そのため、resize
や scroll
など、windowオブジェクトに与えるグローバルイベント以外は極力 on~
アトリビュートでイベント付与することをおすすめします。
入れ子のコンポーネント
<sample>
<company />
</sample>
<company>
<h1>株式会社 部室</h1>
</company>
はじめにマウントさせる処理として riot.mount('sample')
を実行しましたが、入れ子のコンポーネントはルートのコンポーネント(この場合はsample)がマウントされれば、自動でマウントされていきます。
既存タグへの適応:data-is
<sample>
<div data-is="company" />
</sample>
SEO的にカスタムタグでなく既存のタグを用いたい場合は多々あります。
その場合は、data-is
アトリビュートにカスタムタグ名を入れることで、既存タグを活かしたままカスタムタグをマウントすることができます。
入れ子のコンポーネントへの値の受け渡し
<sample>
<div data-is="company" ja="株式会社部室" en="Bushitsu Inc." />
</sample>
<company>
<h1>{opts.ja}({opts.en})</h1>
</company>
カスタムタグをマウントさせる側で好きなアトリビュート名と値を追加します(この場合は ja
と en
)。
そうやって受け渡された値はカスタムタグ側で {opts}
(js上では this.opts
)を経由してアクセスできます。
もちろん、文字列だけでなく <div data-is="company" a={true} b={handleB} />
のように真偽値やコールバック関数を渡すこともできます。
yield
<sample>
<div data-is="company" ja="株式会社部室" en="Bushitsu Inc.">
<p>WEBサイト制作と映像制作をしています。</p>
</div>
</sample>
<company>
<h1>{opts.ja}({opts.en})</h1>
<yield />
</company>
値(変数や関数)の受け渡しはアトリビュート経由で可能なことがわかりましたが、HTML自体を入れ子のコンポーネントに渡す場合は yield
を使います。
上記のコンポーネントがマウントされると、以下のようになり、入れ子のコンポーネントの中に記述したHTMLがそのまま yield
部分と置き換わります。
<div data-is="sample">
<div data-is="company">
<h1>株式会社部室(Bushitsu Inc.)</h1>
<p>WEBサイト制作と映像制作をしています。</p>
</div>
</div>
複数のyield
<sample>
<div data-is="company" ja="株式会社部室" en="Bushitsu Inc.">
<yield to="description">
<p>WEBサイト制作と映像制作をしています。</p>
</yield>
<yield to="free-space">
<p>3Dアニメーションとかも作ってみたいです。</p>
</yield>
</div>
</sample>
<company>
<h1>{opts.ja}({opts.en})</h1>
<yield from="description" />
<yield from="free-space" />
</company>
<yield to="">
と <yield from="">
を用いることで複数のyieldを用いることもできます。