在尝试“以 Rails 方式”组织 JS 文件时,我在 Rails 4 应用程序中遇到了问题。它们以前分散在不同的视图中。我将它们组织成单独的文件并使用资产管道编译它们。然而,我刚刚了解到,当 turbo-linking 打开时,jQuery 的“就绪”事件不会在随后的点击中触发。第一次加载页面时它可以工作。但是当您单击一个链接时,ready( function($) {
内的任何内容都不会被执行(因为该页面实际上并没有再次加载)。很好的解释:here。
所以我的问题是:在 turbo-links 开启时,确保 jQuery 事件正常工作的正确方法是什么?您是否将脚本包装在特定于 Rails 的侦听器中?或者也许 Rails 有一些魔力让它变得不必要?文档对于这应该如何工作有点含糊,尤其是关于通过诸如 application.js 之类的清单加载多个文件。
这就是我所做的...... CoffeeScript:
ready = ->
...your coffeescript goes here...
$(document).ready(ready)
$(document).on('page:load', ready)
最后一行监听页面加载,这是涡轮链接将触发的。
编辑...添加 Javascript 版本(每个请求):
var ready;
ready = function() {
...your javascript goes here...
};
$(document).ready(ready);
$(document).on('page:load', ready);
编辑 2...对于 Rails 5 (Turbolinks 5),page:load
变为 turbolinks:load
,甚至会在初始加载时触发。所以我们可以做到以下几点:
$(document).on('turbolinks:load', function() {
...your javascript goes here...
});
我刚刚了解到解决此问题的另一种选择。如果您加载 the jquery-turbolinks
gem,它会将 Rails Turbolinks 事件绑定到 document.ready
事件,这样您就可以以通常的方式编写 jQuery。您只需在 js 清单文件中的 jquery
之后添加 jquery.turbolinks
(默认情况下:application.js
)。
//= require jquery.turbolinks
添加到清单(例如 application.js)。
最近我发现了最干净、最容易理解的处理方式:
$(document).on 'ready page:load', ->
# Actions to do
或者
$(document).on('ready page:load', function () {
// Actions to do
});
编辑
如果您已将 delegated events 绑定到 document
,请确保将它们附加到 ready
函数之外,否则它们将在每个 page:load
事件上反弹(导致相同的功能要运行多次)。例如,如果您有这样的电话:
$(document).on 'ready page:load', ->
...
$(document).on 'click', '.button', ->
...
...
将它们从 ready
函数中取出,如下所示:
$(document).on 'ready page:load', ->
...
...
$(document).on 'click', '.button', ->
...
绑定到 document
的委托事件不需要绑定到 ready
事件。
ready()
函数的公认答案要简单得多。对 ready
函数之外的绑定委托事件的解释进行了额外的投票。
$(document).on( "ready", handler ), deprecated as of jQuery 1.8.
jquery/ready
ready
部分无效?
在 Rails 4 documentation 中找到了这个,类似于 DemoZluk 的解决方案,但略短:
$(document).on 'page:change', ->
# Actions to do
或者
$(document).on('page:change', function () {
// Actions to do
});
如果您有调用 $(document).ready()
的外部脚本,或者如果您不想重写所有现有的 JavaScript,那么此 gem 允许您继续将 $(document).ready()
与 TurboLinks 一起使用:https://github.com/kossnocorp/jquery.turbolinks
根据新的 rails guides,正确的方法是执行以下操作:
$(document).on('turbolinks:load', function() {
console.log('(document).turbolinks:load')
});
或者,在咖啡脚本中:
$(document).on "turbolinks:load", ->
alert "page has loaded!"
不要监听事件 $(document).ready
,只会触发一个事件。毫不奇怪,无需使用 jquery.turbolinks gem。
这适用于 rails 4.2 及更高版本,不仅适用于 rails 5。
"turbolinks:load"
事件在 Rails 4.2 中有效? turbolinks:
事件前缀是在 New Turbolinks 中引入的,在使用 Turbolinks Classic 的 Rails 4.2 IIRC 中没有使用。如果 "turbolinks:load"
不适用于您的 Rails 5 之前的应用程序,请考虑尝试 "page:change"
。请参阅guides.rubyonrails.org/v4.2.7/…
page:change
或升级 turbolinks。还发现这一点,可能与某些相关,其中 turbolinks 将事件转换为旧事件名称:github.com/turbolinks/turbolinks/blob/v5.0.0/src/turbolinks/…
alert "page has loaded!"
是否需要缩进才能由回调函数实际运行?
注意:请参阅@SDP 的答案以获得干净的内置解决方案
我将其修复如下:
通过更改包含顺序,确保在包含其他依赖于应用程序的 js 文件之前包含 application.js:
// in application.js - make sure `require_self` comes before `require_tree .`
//= require_self
//= require_tree .
定义一个处理 application.js
中的绑定的全局函数
// application.js
window.onLoad = function(callback) {
// binds ready event and turbolink page:load event
$(document).ready(callback);
$(document).on('page:load',callback);
};
现在您可以绑定以下内容:
// in coffee script:
onLoad ->
$('a.clickable').click =>
alert('link clicked!');
// equivalent in javascript:
onLoad(function() {
$('a.clickable').click(function() {
alert('link clicked');
});
ready
事件挂钩,这意味着您可以使用“标准”初始化方式:$(document).ready(function() { /* do your init here */});
。加载完整页面时应调用您的初始化代码(-> 没有 turbolinks),当您通过 turbolinks 加载页面时应再次执行您的初始化代码。如果您只想在使用 turbolink 时执行某些代码:$(document).on('page:load', function() { /* init only for turbolinks */});
以上都不适合我,我通过不使用 jQuery 的 $(document).ready 解决了这个问题,而是使用 addEventListener。
document.addEventListener("turbolinks:load", function() {
// do something
});
$(document).on 'ready turbolinks:load', ->
console.log '(document).turbolinks:load'
turbolinks:load
,但 Safari 并没有,而且修复它的 hacky 方法(在 application.js
上触发 turbolinks:load
)显然会破坏 Chrome(它会因此触发两次)。这是正确的答案。一定要参加 2 个事件 ready
和 turbolinks:load
。
你必须使用:
document.addEventListener("turbolinks:load", function() {
// your code here
})
要么使用
$(document).on "page:load", attachRatingHandler
或者使用jQuery的.on函数来达到同样的效果
$(document).on 'click', 'span.star', attachRatingHandler
有关详细信息,请参见此处:http://srbiv.github.io/2013/04/06/rails-4-my-first-run-in-with-turbolinks.html
您可能希望在 page:load
触发时触发 ready
事件,而不是使用变量来保存“就绪”函数并将其绑定到事件。
$(document).on('page:load', function() {
$(document).trigger('ready');
});
这是我为确保事情不会执行两次所做的工作:
$(document).on("page:change", function() {
// ... init things, just do not bind events ...
$(document).off("page:change");
});
我发现使用 jquery-turbolinks
gem 或组合 $(document).ready
和 $(document).on("page:load")
或单独使用 $(document).on("page:change")
的行为会出乎意料 - 特别是如果您正在开发中。
$(document).off
位的简单警报,它显然会在我到达该页面时发出警报。但至少在运行 WEBrick 的开发中,当我单击另一个页面的链接时,它也会发出警报。更糟糕的是,当我单击返回原始页面的链接时,它会发出两次警报。
我发现以下 article 对我很有用,并详细说明了以下内容的使用:
var load_this_javascript = function() {
// do some things
}
$(document).ready(load_this_javascript)
$(window).bind('page:change', load_this_javascript)
我想我会把这个留给那些升级到 Turbolinks 5 的人:修复代码的最简单方法是从:
var ready;
ready = function() {
// Your JS here
}
$(document).ready(ready);
$(document).on('page:load', ready)
至:
var ready;
ready = function() {
// Your JS here
}
$(document).on('turbolinks:load', ready);
参考:https://github.com/turbolinks/turbolinks/issues/9#issuecomment-184717346
$(document).ready(ready)
$(document).on('turbolinks:load', ready)
turbolinks:load
事件会在初始页面加载以及跟随链接之后触发。如果您将一个事件同时附加到标准 ready
事件和 turbolinks:load
事件,它会在您第一次访问页面时触发两次。
ready
在后续页面加载时触发两次。请更改或删除它。
测试了这么多解决方案终于到了这个。这么多你的代码绝对不会被调用两次。
var has_loaded=false; var ready = function() { if(!has_loaded){ has_loaded=true; // 这里是你的 } } $(document).ready(ready); $(document).bind('page:change', ready);
我通常为我的 rails 4 项目执行以下操作:
在 application.js
function onInit(callback){
$(document).ready(callback);
$(document).on('page:load', callback);
}
然后在其余的 .js 文件中,我不使用 $(function (){})
,而是调用 onInit(function(){})
首先,安装 jquery-turbolinks
gem。然后,不要忘记将包含的 Javascript 文件从 application.html.erb
的正文末尾移动到其 <head>
。
作为 described here,如果您出于速度优化的原因将应用程序 javascript 链接放在页脚中,则需要将其移动到标记中,以便它在标记中的内容之前加载。这个解决方案对我有用。
我发现在使用 ready
和 turbolinks:load
的函数时我的函数加倍,所以我使用了,
var ready = function() {
// you code goes here
}
if (Turbolinks.supported == false) {
$(document).on('ready', ready);
};
if (Turbolinks.supported == true) {
$(document).on('turbolinks:load', ready);
};
这样,如果支持 turbolinks,您的功能就不会翻倍!
var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready)
.ready
和'page:load'
是否会被触发?ready
事件。如果是 turbolinks 加载,仅page:load
事件会被触发。ready
和page:load
不可能在同一页面上被触发。page:load
和ready
。$(document).on('page:load ready', ready);
第二个参数只是一个函数,它恰好被命名为ready
,按照这个答案的例子。