進行形:Chaplin.js のページ遷移でフェードアウトがぶつ切りになる問題


Chaplin.js はメモリ管理がきっちりしているので、画面遷移時に古い controller およびその管理下にある view や model をきれいさっぱり片付けてくれます。

これはこれでとても良い。けれど、例えば Bootstrap の Modal を使って確認ダイアログを出している場合、次画面への遷移時にフェードアウトの処理がぶった切られて、全画面カバーが残ったままになったりします。切ないですね。

そもそも Chaplin ではページ遷移エフェクトをサポートしていない(メモリ管理を優先・徹底するためのトレードオフであり、設計思想でもある)ため、こういった問題についてはアプリ側で対処することになります。

ひとまず手持ちの対処法晒すのですが、どれもイマイチなので、突っ込みもらいたいなと。Chaplin しか知らないので、Angular とか、他の SPA 用フレームワークならこんな冴えたやり方あるぜ、ってのでもいいです。

案1:view.dispose でゴミ掃除

遷移前に dispose される側の view でエフェクトの残骸を消します。Bootstrap の Modal はネストできないので、処理は共通化できます。ベースの view に実装するのが簡単かなと。

view.coffee
class EditView extends View
  dispose: ->
    $('body').removeClass("modal-open")
    $('.modal-backdrop').remove()
    super()
...

実装は単純で良いですが、エフェクトがぶった切られるのはそのままです。しかし、キビキビ感が出るからこれでいいという人もいるかもしれない。遷移しないならフェードアウトは欲しいけど、遷移する場合はスパっとと切り替わって欲しいという感覚が、なんとなくあるような気がしますが、どうなんでしょう。。。

案2:view から controller にエフェクト終了通知をあげる

エフェクトの終了時に view からイベントを上げます。イベントを受け取った controller は明示的に遷移を行います。

controller.coffee
class EditController extends Controller
  show: ->
    @view = new EditView
      region: 'main'
      model: new Model()
    @listenTo(@view, 'dialogClosed', @transition)

  transition: ->
    @redirectTo url: "/foo/bar"

  ....
view.coffee
class EditView extends View
  events:
    'click #action', 'notifyDialogClosed'

  notifyDialogClosed: ->
    dialog = $("#confirmDialog")
    dialog.on 'hidden.bs.modal', =>
      @trigger('dialogClosed')

    dialog.modal('hide')

  ...

エフェクトが完全に終わるまで待ってから遷移するので、その点は良いですが、案1と比較するとずいぶん回りくどくなってます。また、Bootstrap の Modal でせっかく全画面カバーしているのに、遷移前に一瞬だけそれが解除されてしまいます。さらに、もっさり感もアップします。というわけで、正直使えないです。

案3:エフェクトを使わない

身も蓋もないですが、そもそも問題がなかったことにしてしまう。業務アプリなら、これもアリな気がしますが。

現在進行形

というわけで、アプリ側でできることをあげてみました。また何か思いついたら書き足します。

参考