たとえばログインが完了したときとか、データの保存に成功したときとか、
ユーザーに対して処理の結果を 簡易的にフィードバックしたいことがあるわけです。
Railsだとflashという仕組みで簡単にできますね。
これをRiot.jsでもやりたい!ということでやってみました。
デザインにはおしゃれで有名なSemanticUIを使っていますが、bootstrapとかでも同じような書き方できるはず。SemanticUIおすすめ。
完成イメージ
環境
- riot.js v3.0.0
- SemanticUI v2.2.4
きましたv3!
メッセージを別タグにして読み込む
ログイン完了したあととかって、だいたい画面遷移するじゃないですか。
なので通知メッセージはタグ横断で表示したい。
ということでまずはメッセージ部分をflash.tagとして切り出し、
index.htmlでもろもろ読み込みの設定をします。
(ページごとの内容を<content>
に出力するSPA的な想定です)
...
<body>
<header></header>
<div>
<flash></flash><!-- ここにメッセージ表示するよ -->
<content></content>
</div>
<footer></footer>
...
<script>
...
var obs = riot.observable();
</script>
</body>
observableつかうよ
var obs = riot.observable();
タグ間で動作を連携させたいので、observableを使います。
というか今回はじめてつかった。便利!
ここではまだobservableを用意しただけ。
この後こいつのイベントを発火させ、それを受け取ることで、タグ間で動作を連携させます。
こちらの記事が大変わかりやすかったです。
flash.tagを実装する
お次はflash.tag
の中身を実装します。これが今回のメイン。
html部分はSemanticUIのmessageをほぼそのまま使ってるだけなので、非常にシンプル。cssもお好みで調整してください。
flashオブジェクトを受け取ったらメッセージが表示されるようになってて、flash.type
とflash.text
でメッセージの色と本文を設定できるようにしています。
(typeにはsuccess
とかerror
とかが入るイメージ)
<flash>
<div id="flasher" if={flash}>
<div class="ui attached message {flash.type}">
<i class="close icon" onclick={ close }></i>
<div class="header">{flash.text}</div>
</div>
</div>
<style>
#flasher {
width: 100%;
position: fixed;
z-index: 100;
opacity: 0.9;
}
</style>
<script>
var that = this
close(ms=0) {
setTimeout(function(){
$('#flasher').transition('fade')
that.flash = null
that.update()
}, ms)
}
obs.on("flashChanged", function(obj) {
that.flash = obj
that.update()
that.close(3000)
})
</script>
</flash>
一番下で、さっきのobservableがflashChanged
というトリガーを受け取ったときのイベントを定義しています。
といってもやってることは非常にシンプルで、flashオブジェクトを受け取って画面を更新してるだけです。
これだけでもいいのですが、今回は数秒たつと自動で消えるようにしたかったので、close()
メソッドをを定義して最後に呼び出しています。
Semanticで用意してくれてるtransition('fade')
でふわっと消えるのがいい感じ。
メッセージを表示する
最後にイベント発火側の記述。
これも非常にシンプルです。
if(success) {
obs.trigger("flashChanged", {type:'success',text:'ログインしました'})
}else {
obs.trigger("flashChanged", {type:'error',text:'ログインに失敗しました'})
}
おまけ
同じようにして、ページ全体にローディング画面を表示するタグも作ってみました。
<dimmer>
<div class="ui page dimmer {state}">
<div class="ui indeterminate huge text loader">Loading</div>
</div>
<script>
var that = this
obs.on("dimmerChanged", function(state) {
that.state = state
that.update()
})
</script>
</dimmer>
obs.trigger("dimmerChanged", 'active')
signup().then(
function() {
obs.trigger("dimmerChanged", '')
})
)
こんな感じになりました。
まとめ
という感じで非常にお手軽にメッセージ通知機能ができました。
observable便利!