Turbolinksでアプリを開発するには、スムーズに動作させるために特別な方法が必要です。ページがロードされてキャッシュされる方法の違いによって、実行中のスクリプトのいくつかのパターンは、Turbolinksと同等の方法では動作しません。これは最初は不愉快に思えるかもしれませんが、「落ち着き」はイライラするかもしれませんが、少し理解すれば、より組織的で堅牢なコードを奨励しています:)
あなたが理解したように、スイッチは、プラグインが同じ要素に対して複数回呼び出されていることです。これは、Turbolinksがページをちょうどからキャッシュするためです。キャッシュされたバージョンには、動的に追加されたHTML [1]などが含まれています。プラグインを介して追加されたものバック/フォワードをナビゲートすると、キャッシュされたバージョンが復元され、動作は重複します。/
これを修正するにはどうすればよいですか。 HTMLまたはイベントリスナーを追加するコードを操作するときは、ページがキャッシュされる前に振る舞いを解除するのが一般的です。そのためのTurbolinksイベントはturbolinks:before-cache
です。だからあなたのセットアップ/ティアダウンは次のようになります。
// app/assets/javascripts/switches.js
$(document)
.on('turbolinks:load', function() {
$('.switch').bootstrapSwitch()
})
.on('turbolinks:before-cache', function() {
$('.switch').bootstrapSwitch('destroy')
})
すべてのセットアップとティアダウンは、イベントハンドラで行われているので、このテストには少し難しいです。さらに、もっと多くのケースがあるかもしれないので、反復を避けるために、機能を設定し、解体するための独自の「ミニフレームワーク」を導入したいと思うかもしれません。以下では、基本的なフレームワークの作成について説明します。
これは私たちが目指すものです。window.App.addFunction
を名前と関数に呼び出すと、呼び出す関数が登録されます。その関数は要素を取得し、プラグインを呼び出します。アプリの初期化時に私たちは、それぞれの関数を呼び出します
// app/assets/javascripts/application.js
// …
window.App = {
functions: {},
addFunction: function (name, fn) {
this.functions[name] = fn
}
}
、および:
// app/assets/javascripts/switches.js
window.App.addFunction('switches', function() {
var $switches = $('.switch').bootstrapSwitch()
return {
destroy: function() {
$switches.bootstrapSwitch('destroy')
}
}
})
次実装addFunction
、functions
プロパティに追加された機能を格納する:それはティアダウンのためにdestroy
機能を持つオブジェクトを返します。それが存在する場合results
アレイ内の各関数呼び出しの結果を格納します。
// app/assets/javascripts/application.js
// …
var results = []
window.App = {
// …
init: function() {
for (var name in this.functions) {
var result = this.functions[name]()
if (result) results.push(result)
}
}
}
テ
// app/assets/javascripts/application.js
// …
window.App = {
// …
destroy: function() {
for (var i = 0; i < results.length; i++) {
var result = results[i]
if (typeof result.destroy === 'function') result.destroy()
}
results = []
}
}
は最後に初期化してアプリをティアダウン:
$(document)
.on('turbolinks:load', function() {
window.App.init.call(window.App)
})
.on('turbolinks:before-cache', window.App.destroy)
だから、すべて一緒にこれを置くために:
;(function() {
var results = []
window.App = {
functions: {},
addFunction: function (name, fn) {
this.functions[name] = fn
},
init: function() {
for (var name in this.functions) {
var result = this.functions[name]()
if (result) results.push(result)
}
},
destroy: function() {
for (var i = 0; i < results.length; i++) {
var result = results[i]
if (typeof result.destroy === 'function') result.destroy()
}
results = []
}
}
$(document)
.on('turbolinks:load', function() {
window.App.init.call(window.App)
})
.on('turbolinks:before-cache', window.App.destroy)
})()
アプリをダウンARINGしても、結果に(存在する場合)
destroy
を呼び出して破壊する必要
関数は、関数を呼び出すイベントハンドラから独立しています。このデカップリングには2つの利点があります。最初にもっとテスト可能です:関数はwindow.App.functions
で利用できます。また、いつ機能を呼び出すかを選択することもできます。たとえば、ターボリンクを使用しないと決めた場合、変更する必要があるのはwindow.App.init
と呼ばれる部分だけです。
は、[1]私は、これは(それが最初にロードされたとき、それがあったようにページに戻って、ユーザーを返す「戻る」を押し)、デフォルトのブラウザの動作よりも優れていると思います。 Turbolinksの "Back"は、ユーザーがページを離れたときにそのページに戻ってきます。おそらくユーザーが期待しているものです。
私はTurboLinksについてよく知りませんが、簡単な回避策があると思います。以前に '.bootstrapSwitch();'が呼び出されたかどうかをテストするラッパー関数を作成してみてくださいそれは最初の実行で... – Myst