ChatGPT解决这个技术问题 Extra ChatGPT

Rails 4:如何将 $(document).ready() 与 turbo-links 一起使用

在尝试“以 Rails 方式”组织 JS 文件时,我在 Rails 4 应用程序中遇到了问题。它们以前分散在不同的视图中。我将它们组织成单独的文件并使用资产管道编译它们。然而,我刚刚了解到,当 turbo-linking 打开时,jQuery 的“就绪”事件不会在随后的点击中触发。第一次加载页面时它可以工作。但是当您单击一个链接时,ready( function($) { 内的任何内容都不会被执行(因为该页面实际上并没有再次加载)。很好的解释:here

所以我的问题是:在 turbo-links 开启时,确保 jQuery 事件正常工作的正确方法是什么?您是否将脚本包装在特定于 Rails 的侦听器中?或者也许 Rails 有一些魔力让它变得不必要?文档对于这应该如何工作有点含糊,尤其是关于通过诸如 application.js 之类的清单加载多个文件。


Y
Yannick Schuchmann

这就是我所做的...... 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...

});

是咖啡脚本吗?我还没学会呢。是否有与您的示例等效的 js 或 jQuery?
我想我明白了:var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready) .ready'page:load' 是否会被触发?
@Emerson 有一个非常有用的网站,有一个明确的名称:js2coffee.org
我可以确认 ready 函数确实 not 被调用了两次。如果是硬刷新,会触发 ready 事件。如果是 turbolinks 加载, page:load 事件会被触发。 readypage:load 不可能在同一页面上被触发。
仅供参考,您还可以通过为第一个参数包含一个空格分隔的字符串,将其应用于多个事件 page:loadready$(document).on('page:load ready', ready); 第二个参数只是一个函数,它恰好被命名为 ready,按照这个答案的例子。
u
user664833

我刚刚了解到解决此问题的另一种选择。如果您加载 the jquery-turbolinks gem,它会将 Rails Turbolinks 事件绑定到 document.ready 事件,这样您就可以以通常的方式编写 jQuery。您只需在 js 清单文件中的 jquery 之后添加 jquery.turbolinks(默认情况下:application.js)。


太好了,谢谢!正是我需要的。铁轨方式。习俗。
根据 documentation,您应该将 //= require jquery.turbolinks 添加到清单(例如 application.js)。
@wildmonkey 这两个答案是互斥的。 0.o
添加此 gem 时需要重新启动 Rails 服务器
请注意,Rails 4 现在默认使用 Turbolinks 5,而 jquery.turbolinks 又不支持它!请参阅github.com/kossnocorp/jquery.turbolinks/issues/56
C
Christian

最近我发现了最干净、最容易理解的处理方式:

$(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
@Dezi @mfazekas 如果您使用的是早期版本的 jQuery,并且没有 jquery-turbolinks gem,这个解决方案会起作用吗?还是使用 gem 使 ready 部分无效?
最简单和最简单的方法。它支持分布在多个文件中的 js 代码,我不必担心它们的包含顺序。比变量赋值要干净得多。
您可能应该使用“page:change”而不是“page:load”作为 the former is fired whether the page is loaded from the server or from client-side cache
m
migu

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


V
Vedant Agarwala

根据新的 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。


很好,这对我有用。在此处尝试解决方案:stackoverflow.com/questions/17881384/… 但由于某种原因无法正常工作。现在我加载 turbolinks:load 代替
谁能确认 "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/…
@EliotSykes 该指南尚未更新。 Rails 4.2 现在使用 github.com/turbolinks/turbolinks 而不是 turbolinks-classic。无论如何,这取决于您在 Gemfile 中指定的内容。希望你能尽快确认:)
谢谢@vedant1811。在撰写本文时,我确认一个新的 Rails 4.2.7 应用程序使用 Turbolinks 5(不是 turbolinks-classic)。阅读本文的开发人员 - 检查您的 Gemfile.lock 以了解使用的 turbolinks 版本。如果低于 5.0,则使用 page:change 或升级 turbolinks。还发现这一点,可能与某些相关,其中 turbolinks 将事件转换为旧事件名称:github.com/turbolinks/turbolinks/blob/v5.0.0/src/turbolinks/…
alert "page has loaded!" 是否需要缩进才能由回调函数实际运行?
s
sled

注意:请参阅@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');
});

这似乎是最干净的,因为您只需在一个地方添加它,而不是每个咖啡脚本文件。干得好!
@sled那么这句话是说使用SDP的使用gem和这段代码的方法吗?或者这是一个不使用宝石的答案?
忘记这个答案并使用SDP的解决方案。
@sled 是否可以将 SDP 的解决方案与仅将呼叫放在一个地方的概念结合起来?
@gwho:正如 SDP 的回答所示,turbolinks 与 ready 事件挂钩,这意味着您可以使用“标准”初始化方式:$(document).ready(function() { /* do your init here */});。加载完整页面时应调用您的初始化代码(-> 没有 turbolinks),当您通过 turbolinks 加载页面时应再次执行您的初始化代码。如果您只想在使用 turbolink 时执行某些代码:$(document).on('page:load', function() { /* init only for turbolinks */});
R
RockL

以上都不适合我,我通过不使用 jQuery 的 $(document).ready 解决了这个问题,而是使用 addEventListener。

document.addEventListener("turbolinks:load", function() {
  // do something
});

B
Baum mit Augen
$(document).on 'ready turbolinks:load', ->
  console.log '(document).turbolinks:load'

这是唯一适用于每个浏览器的解决方案,对于 Turbolinks >= 5 并且在第一页加载以及单击任何链接(使用 turbolinks)时都会触发。之所以如此,是因为虽然 Chrome 在第一个页面加载时触发 turbolinks:load,但 Safari 并没有,而且修复它的 hacky 方法(在 application.js 上触发 turbolinks:load)显然会破坏 Chrome(它会因此触发两次)。这是正确的答案。一定要参加 2 个事件 readyturbolinks:load
G
Gian Franco Fioriello

你必须使用:

document.addEventListener("turbolinks:load", function() {
  // your code here
})

from turbolinks doc


d
derekyau

要么使用

$(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


w
wachunei

您可能希望在 page:load 触发时触发 ready 事件,而不是使用变量来保存“就绪”函数并将其绑定到事件。

$(document).on('page:load', function() {
  $(document).trigger('ready');
});

G
Gray Kemmey

这是我为确保事情不会执行两次所做的工作:

$(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") 的行为会出乎意料 - 特别是如果您正在开发中。


你介意解释一下你所说的意外行为是什么意思吗?
如果我在上面的匿名“page:change”函数中只有一个没有 $(document).off 位的简单警报,它显然会在我到达该页面时发出警报。但至少在运行 WEBrick 的开发中,当我单击另一个页面的链接时,它也会发出警报。更糟糕的是,当我单击返回原始页面的链接时,它会发出两次警报。
a
atw

我发现以下 article 对我很有用,并详细说明了以下内容的使用:

var load_this_javascript = function() { 
  // do some things 
}
$(document).ready(load_this_javascript)
$(window).bind('page:change', load_this_javascript)

t
tirdadc

我想我会把这个留给那些升级到 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


A
Aamir
$(document).ready(ready)  

$(document).on('turbolinks:load', ready)

虽然此代码段可能会解决问题,但 including an explanation 确实有助于提高帖子的质量。请记住,您正在为将来的读者回答问题,而这些人可能不知道您的代码建议的原因。
实际上,这个答案是不正确的。 turbolinks:load 事件会在初始页面加载以及跟随链接之后触发。如果您将一个事件同时附加到标准 ready 事件和 turbolinks:load 事件,它会在您第一次访问页面时触发两次。
这个答案是不正确的。正如@alexanderbird 所说,它会导致 ready 在后续页面加载时触发两次。请更改或删除它。
@alexanderbird 你的评论为我解决了一个问题
S
Simon Meyborg

测试了这么多解决方案终于到了这个。这么多你的代码绝对不会被调用两次。

var has_loaded=false; var ready = function() { if(!has_loaded){ has_loaded=true; // 这里是你的 } } $(document).ready(ready); $(document).bind('page:change', ready);


m
muZk

我通常为我的 rails 4 项目执行以下操作:

application.js

function onInit(callback){
    $(document).ready(callback);
    $(document).on('page:load', callback);
}

然后在其余的 .js 文件中,我不使用 $(function (){}),而是调用 onInit(function(){})


A
Aboozar Rajabi

首先,安装 jquery-turbolinks gem。然后,不要忘记将包含的 Javascript 文件从 application.html.erb 的正文末尾移动到其 <head>

作为 described here,如果您出于速度优化的原因将应用程序 javascript 链接放在页脚中,则需要将其移动到标记中,以便它在标记中的内容之前加载。这个解决方案对我有用。


L
Lee Eather

我发现在使用 readyturbolinks: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,您的功能就不会翻倍!