Rails 4:如何在Turbo-Links中使用$(document).ready()


422

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

所以我的问题是:什么是确保涡轮链接打开时jQuery事件正常工作的正确方法?您是否将脚本包装在特定于Rails的侦听器中?或者,也许rails有一些使它不必要的魔力?该文档对如何工作有点含糊不清,尤其是在通过清单(如application.js)加载多个文件方面。

Answers:


554

这是我的工作... CoffeeScript:

ready = ->

  ...your coffeescript goes here...

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

最后一行监听页面加载,这是turbo链接将触发的页面加载。

编辑 ...添加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...

});

3
那是咖啡剧本吗?我还没学会 是否有与您的示例等效的js或jQuery?
emersonthis

6
想想我明白了:双方都var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready)担心并被触发吗? .ready'page:load'
emersonthis

4
@Emerson有一个非常有用的网站,名称明确:js2coffee.org
MrYoshiji 2013年

16
我可以证实,准备功能并没有被调用两次。如果是硬刷新,则ready触发该事件。如果是turbolinks负载,则page:load触发该事件。这是不可能都readypage:load在同一页面上被解雇。
基督教徒

7
仅供参考,您还可以将其应用于多个事件,page:loadready为第一个参量添加以空格分隔的字符串。$(document).on('page:load ready', ready);第二个参数只是一个函数,恰好在ready此答案的示例之后被命名为。
ahnbizcad 2014年

235

我刚刚了解了解决此问题的另一种选择。如果加载jquery-turbolinks宝石它将绑定Rails的Turbolinks事件的document.ready事件,这样你就可以用通常的方式写你的jQuery。您只需在js清单文件(默认为:)jquery.turbolinks之后添加即可。jqueryapplication.js


2
很好,谢谢!正是我所需要的。铁轨的方式。惯例。
杰里米·贝克尔

6
根据文档,您应该添加//= require jquery.turbolinks到清单(例如application.js)。
apocryphalauthor 2013年

1
@wildmonkey这两个答案是互斥的。0.o
ahnbizcad 2014年

1
添加此宝石时,您需要重新启动Rails服务器
Toby 1 Kenobi

21
请注意,Rails 4现在默认为Turbolinks 5,而jquery.turbolinks则不支持它!参见github.com/kossnocorp/jquery.turbolinks/issues/56
塞巴斯蒂安

201

最近,我找到了最干净,最容易理解的处理方式:

$(document).on 'ready page:load', ->
  # Actions to do

要么

$(document).on('ready page:load', function () {
  // Actions to do
});

编辑
如果您将委派的事件绑定到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事件。


9
这比创建单独ready()函数的公认答案要简单得多。奖励用于解释在ready函数外部绑定委托事件的解释。
基督教徒

1
这种方法的缺点是$(document).on( "ready", handler ), deprecated as of jQuery 1.8. jquery / ready
mfazekas

@Dezi @mfazekas如果您使用的是早期版本的jQuery,并且没有jquery-turbolinks gem,则此解决方案是否可行?还是ready使用宝石使该部分无效?
ahnbizcad 2014年

最简单,最简单的方法。它支持分布在多个文件中的js代码,我不必理会它们的包含顺序。比变量分配要干净得多。
Evgenia Manolova'3

3
您可能应该使用“ page:change”而不是“ page:load”,因为无论是从服务器还是从客户端缓存加载页面,都会触发前者
内森·朗

91

Rails 4文档中找到了这一点,类似于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


79

按照新的rails指南,正确的方法是执行以下操作:

$(document).on('turbolinks:load', function() {
   console.log('(document).turbolinks:load')
});

或者,在coffeescript中:

$(document).on "turbolinks:load", ->
alert "page has loaded!"

不要听事件$(document).ready,只会触发一个事件。毫不奇怪,无需使用jquery.turbolinks gem。

这适用于4.2或更高版本的导轨,不仅适用于导轨5。


很好,这对我有用。在这里尝试过解决方案:stackoverflow.com/questions/17881384/…,但是由于某些原因无法正常工作。现在,我在turbolinks:load上加载
krinker '16

1
谁能确认该"turbolinks:load"事件在Rails 4.2中有效?该turbolinks:事件前缀是在推出 Turbolinks和Rails的不使用4.2 IIRC它使用Turbolinks 经典。考虑尝试"page:change",如果"turbolinks:load"不能对你的工作前的Rails应用5。参见guides.rubyonrails.org/v4.2.7/…–
艾略特·赛克斯

1
@EliotSykes指南尚未更新。Rails 4.2现在使用github.com/turbolinks/turbolinks代替了turbolinks-classic。无论如何,这取决于您在Gemfile中指定的内容。希望您能尽快确认:)
vedant '16

3
谢谢@ vedant1811 在撰写本文时,我确认一个新的Rails 4.2.7应用程序使用Turbolinks 5(而不是turbolinks-classic)。开发人员请阅读此文章-检查您的Gemfile.lock中所使用的turbolinks版本。如果小于5.0,则使用page:change或升级Turbolink。还发现了这一点,可能与某些地方有关,其中turbolinks将事件转换为旧的事件名称:github.com/turbolinks/turbolinks/blob/v5.0.0/src/turbolinks/…–
Eliot Sykes,

1
是否alert "page has loaded!"需要缩进以由回调函数实际运行?
mbigras

10

注意:有关干净的内置解决方案,请参见@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');
});

2
这似乎是最干净的方法,因为您只需要在一个地方而不是每个coffeescript文件中添加即可。干得好!
–pyrospade

@sled那么这句话是要使用SDP使用gem和此代码的方法吗?还是这是不使用gem的答案?
ahnbizcad 2014年

忘记此答案并使用SDP解决方案。
雪橇

@sled是否可以将SDP解决方案与仅将呼叫放在一个地方的概念结合起来?
ahnbizcad 2014年

1
@gwho:正如SDP的答案所示,turbolinks可以挂接到ready事件,这意味着您可以使用“标准”的初始化方式:$(document).ready(function() { /* do your init here */});。当加载整个页面时,应调用您的初始化代码(->不使用Turbolinks),而当您通过Turbolinks加载页面时,应再次执行您的初始化代码。如果您只想在使用Turbolink时执行一些代码:$(document).on('page:load', function() { /* init only for turbolinks */});
雪橇

8

以上都不适合我,我通过不使用jQuery的$ {document).ready来解决此问题,而是使用addEventListener来解决。

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

7
$(document).on 'ready turbolinks:load', ->
  console.log '(document).turbolinks:load'

对于Turbolinks> = 5,这是唯一适用于所有浏览器的解决方案,该解决方案在首页加载以及单击任何链接(带有turbolinks)时都会触发。这是因为,虽然Chrome浏览器触发的情况下turbolinks:load在第一个页面加载,Safari不和哈克的方式来解决它(触发turbolinks:loadapplication.js)显然打破了Chrome浏览器(与此两次触发)。这是正确的答案。绝对参加2个比赛readyturbolinks:load
lucasarruda



2

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

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

2

这是我做的确保没有两次执行的操作:

$(document).on("page:change", function() {
     // ... init things, just do not bind events ...
     $(document).off("page:change");
});

我发现使用jquery-turbolinksgem或进行组合$(document).ready和/ $(document).on("page:load")$(document).on("page:change")单独使用都会表现出异常情况-特别是在开发中。


您介意解释意想不到的行为吗?
sunnyrjuneja 2015年

如果我只有一个简单的警报,而上面的$(document).off匿名“ page:change”功能中没有任何内容,那么当我进入该页面时,它显然会发出警报。但是至少在运行WEBrick的开发中,当我单击指向另一个页面的链接时,它也会发出警报。更糟糕的是,当我单击链接返回原始页面时,它会发出两次警报。
Gray Kemmey,2015年

2

我发现以下文章对我非常有用,并且详细介绍了以下内容的用法:

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


2
$(document).ready(ready)  

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

2
尽管此代码段可以解决问题,但提供说明确实有助于提高您的帖子质量。请记住,您将来会为读者回答这个问题,而这些人可能不知道您提出代码建议的原因。
andreas

4
实际上,这个答案是不正确的。该turbolinks:load事件在初始页面加载以及跟随以下链接后触发。如果您同时将事件附加到标准ready事件和turbolinks:load事件中,则在您首次访问页面时它将触发两次。
alexanderbird

这个答案是不正确的。就像@alexanderbird所说的那样,它会ready在随后的页面加载中触发两次。请更改或删除它。
彻斯特,

@alexanderbird您的评论为我解决了一个问题
Anwar

1

经过这么多测试的解决方案终于来到了这一点。这么多您的代码绝对不会被调用两次。

      var has_loaded=false;
      var ready = function() {
        if(!has_loaded){
          has_loaded=true;
           
          // YOURJS here
        }
      }

      $(document).ready(ready);
      $(document).bind('page:change', ready);


1

我通常对Rails 4项目执行以下操作:

application.js

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

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


0

首先,安装jquery-turbolinksgem。然后,别忘了将包含的Javascript文件从正文结尾application.html.erb移至<head>

如此处所述,如果出于速度优化的原因将应用程序javascript链接放在页脚中,则需要将其移动到代码中,以便在代码内容之前加载。这个解决方案对我有用。


0

我发现在将函数用于时我的函数加倍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,您的功能就不会加倍!

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.