2017-04-05 60 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”将用户返回到页面,这可能是用户期望的。