2017-04-05 59 views
1

我完全理解爲什麼Turbolinks 5很棒,如果你正在閱讀它,你可能也會這樣做,但是我對它與塊上的其他腳本玩得有多糟糕感到非常沮喪。Turbolinks不友好?

迄今爲止,沒有簡單的解釋(人類可讀)顯示如何以允許它們運行的​​方式包裝現有的jQuery腳本。拿這個例子:https://github.com/Bttstrp/bootstrap-switch。它寫得很好,很容易理解。您可以將js和css加載到您的資產管道中,並在某個頁面上實例化它。

# view.html.erb 
<input type="checkbox" class="switch"> switch button 
<script type="text/javascript"> 
    $(".switch").bootstrapSwitch(); 
</script> 

你去view.html,點擊另一個頁面,點擊返回,你會看到兩個按鈕。

接下來,您花了5個小時尋找一種方法讓Turbolinks只加載一次bootstrapSwitch的實例,如果之前沒有加載過。那麼,即使你這樣做,功能也將消失。點擊它不起作用。

$(document).on("turbolinks:load", function()...將其加載的TurboLink每次訪問,並就目前而言,唯一的辦法,我可以讓它工作,而不是創建副本是在view.html禁用緩存,

<%= content_for :head do %> 
    <meta name="turbolinks-cache-control" content="no-cache"> 
<% end %> 

這感覺有點傻。

我認爲這一切都與使用idempotent - https://github.com/turbolinks/turbolinks#making-transformations-idempotent有關,但你如何幾乎這樣做?

有人可以請這個簡單的插件爲例,並分享一個簡單,優雅的解決方案,使其工作,然後我們可以重現與其他腳本?

+1

我只是經過並且對TurboLinks不太瞭解,但我認爲這是一個簡單的解決方法...嘗試編寫一個包裝函數來測試是否在調用'.bootstrapSwitch();'之前並且只調用它在第一次運行... – Myst

回答

0

使用Turbolink開發應用程序確實需要特定的方法才能讓事情順利進行。由於頁面加載和緩存的方式不同,某些運行腳本模式的行爲與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並註冊一個名稱和功能。該函數獲取元素並調用插件。它返回一個對象與destroy功能拆解:

// app/assets/javascripts/switches.js 
window.App.addFunction('switches', function() { 
    var $switches = $('.switch').bootstrapSwitch() 
    return { 
    destroy: function() { 
     $switches.bootstrapSwitch('destroy') 
    } 
    } 
}) 

以下工具addFunction,增加存儲功能,在functions屬性:

// app/assets/javascripts/application.js 
// … 
window.App = { 
    functions: {}, 

    addFunction: function (name, fn) { 
    this.functions[name] = fn 
    } 
} 

我們會打電話給每個功能時,應用程序初始化,並每個函數調用的結果存儲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) 
    } 
    } 
} 

特aring刪除了應用涉及破壞任何結果調用destroy(如果存在的話):

// 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) 
})() 

函數現在獨立於調用它們的事件處理函數。這種解耦有幾個好處。首先它是更可測試的:功能可在window.App.functions中獲得。您也可以選擇何時調用您的功能。例如,假設您決定不使用Turbolinks,則只需調用window.App.init即可。


[1]我想這是不是默認的瀏覽器的行爲(如果按「後退」返回用戶返回到頁面,因爲它是第一次加載時它)更好。 Turbolinks「Back」將用戶返回到頁面,這可能是用戶期望的。