Riot.jsでobservableを使って簡易的な通知メッセージを表示する


たとえばログインが完了したときとか、データの保存に成功したときとか、
ユーザーに対して処理の結果を 簡易的にフィードバックしたいことがあるわけです。

Railsだとflashという仕組みで簡単にできますね。

flash - Railsドキュメント

これをRiot.jsでもやりたい!ということでやってみました。

デザインにはおしゃれで有名なSemanticUIを使っていますが、bootstrapとかでも同じような書き方できるはず。SemanticUIおすすめ。

完成イメージ

環境

  • riot.js v3.0.0
  • SemanticUI v2.2.4

きましたv3!

メッセージを別タグにして読み込む

ログイン完了したあととかって、だいたい画面遷移するじゃないですか。
なので通知メッセージはタグ横断で表示したい。

ということでまずはメッセージ部分をflash.tagとして切り出し、
index.htmlでもろもろ読み込みの設定をします。
(ページごとの内容を<content>に出力するSPA的な想定です)

index.html
...
<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を用意しただけ。
この後こいつのイベントを発火させ、それを受け取ることで、タグ間で動作を連携させます。

こちらの記事が大変わかりやすかったです。

【Riot.js】タグ間で動作を連動させる - Qiita

flash.tagを実装する

お次はflash.tagの中身を実装します。これが今回のメイン。

html部分はSemanticUIのmessageをほぼそのまま使ってるだけなので、非常にシンプル。cssもお好みで調整してください。

flashオブジェクトを受け取ったらメッセージが表示されるようになってて、flash.typeflash.textでメッセージの色と本文を設定できるようにしています。
(typeにはsuccessとかerrorとかが入るイメージ)

flash.tag
<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')でふわっと消えるのがいい感じ。

メッセージを表示する

最後にイベント発火側の記述。
これも非常にシンプルです。

auth.tag
if(success) {
  obs.trigger("flashChanged", {type:'success',text:'ログインしました'})
}else {
  obs.trigger("flashChanged", {type:'error',text:'ログインに失敗しました'})
}

おまけ

同じようにして、ページ全体にローディング画面を表示するタグも作ってみました。

dimmer.tag
<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>
auth.tag
obs.trigger("dimmerChanged", 'active') 

signup().then(
  function() {
    obs.trigger("dimmerChanged", '')
  })
)

こんな感じになりました。

まとめ

という感じで非常にお手軽にメッセージ通知機能ができました。
observable便利!