我将我的应用程序迁移到Ruby on Rails 5(v5.2.2),我正在尝试使用Turbolinks 5(v5.2.0)。
在我的应用程序中,我有查看包含<script>
元素的文件,我想让它们正确使用Turbolinks(其documentation声明避免脚本元素并使用turbolinks:load
事件)。我要做什么?
也就是说,例如,我有:
# app/views/.../_partial_template.html.erb
<script type="text/javascript">
$(document).ready(function () {
$.ajax({...})
});
// Note: I tried to use $(document).on('turbolinks:load', function() {...});
// and it seems that the JS code runs twice (or more) on every page load.
// I also tried to use <script type="text/javascript" data-turbolinks-eval="false">...</script>
// without success.
</script>
我应该如何重构上面的代码以使其适用于Turbolinks?
奖金:
Turbolinks documentation说:您可以使用内联正文脚本来设置每页JavaScript状态或引导客户端模型。 “每页JavaScript状态”和“引导客户端模型”是什么意思?
如果您的内联脚本包含在<body>
的底部(或者如果它们没有立即操作DOM),那么您可以从$(document).ready…
函数中删除代码,并让它们按预期工作。
通常不鼓励使用内联脚本,因为传统上他们已经指出代码只会在其包含的页面上运行,并且当用户导航时,任何事件侦听器都将被自动销毁。但是,在Turbolinks应用程序中,情况并非如此。如果在内联脚本中添加事件侦听器(并且不删除它),它将继续侦听并在后续页面加载时运行。正如您通过以这种方式设置turbolinks:load
事件侦听器所发现的那样,处理程序在后续页面加载时触发,并且在重新访问第一页时,再次添加了事件侦听器,从而导致重复调用。
关于设置“每页JavaScript状态”和“引导客户端模型”,假设您有一个日历页面,您希望通过一些JavaScript来增强它。您可能有一个处理此问题的Calendar
JavaScript类,因此您可以包含以下内容以使用一些JSON引导它:
<script>new Calendar(<%= @calendar.to_json %>)</script>
(请记住,在Calender
类中设置的任何添加的事件监听器应该在某些时候被销毁,例如turbolinks:before-cache
)。
这证明了这个想法,但在这种情况下更好的方法可能是建立一个查找日历元素的系统,然后在DOM中实例化它们。例如:
<div data-component="calendar" data-props="<%= @calendar.to_json %>">…</div>
然后在您的JavaScript中(包含在应用程序包中):
;(function () {
var calendar
$(document).on('turbolinks:load', function () {
var $el = $('[data-component=calendar]')
if ($el.length) calendar = new Calender($el.data('props'))
})
$(document).on('turbolinks:before-cache', function () {
if (calendar) {
calendar.destroy() // to teardown any event listeners etc
calender = null
}
})
})()
这种方法可以概括,我在这里完成了一个实现:https://stackoverflow.com/a/44057187/783009
希望有所帮助!