我将我的应用程序迁移到 Ruby on Rails 5 (v5.2.2) 并且我正在尝试使用 Turbolinks 5 (v5.2.0)。
在我的应用程序中,我有包含 <script>
的 View 文件元素,我想让它们正确地与 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
希望对您有所帮助!
关于javascript - 使用 Turbolinks 5 重构内联 <script> 元素,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55174436/