javascript - ruby on rails圣经




Rails 4:如何使用$(document).ready()和turbo-links (13)

我在试图组织JS文件“rails方式”时遇到了Rails 4应用程序中的一个问题。 他们以前分散在不同的意见。 我将它们组织成单独的文件并使用资产管道进行编译。 不过,我刚刚了解到,在启用turbo链接时,jQuery的“ready”事件不会触发随后的点击。 你第一次加载一个页面它的工作。 但是当你点击一个链接时, ready( function($) {任何内容都不会被执行(因为页面实际上并没有再次加载)。

所以我的问题是:什么是正确的方式来确保jQuery事件正常运行,而涡轮链接? 你是否将这些脚本包装在一个Rails特定的侦听器中? 或者,也许铁轨有一些魔法,使它不必要? 这些文档对于如何工作有些模糊,尤其是在通过像application.js这样的清单载入多个文件方面。


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

不是使用变量来保存“就绪”函数并将其绑定到事件,而是可以在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.addEventListener("turbolinks:load", function() {
  // your code here
})

来自turbolinks doc


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


我发现下面的article非常适合我,并详细介绍了以下内容的用法:

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

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

application.js

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

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


最近我发现了最简单易懂的处理方式:

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

要么

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

编辑
如果已将委托事件绑定到document ,请确保将它们附加到ready函数之外,否则它们会在每个page:load上反弹page:load事件(导致多次运行相同的函数)。 例如,如果您有任何类似的电话:

$(document).on 'ready page:load', ->
  ...
  $(document).on 'click', '.button', ->
    ...
  ...

把它们从ready函数中拿出来,像这样:

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

$(document).on 'click', '.button', ->
  ...

绑定到document委托事件不需要绑定在ready事件上。


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

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

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



首先,安装jquery-turbolinks宝石。 然后,不要忘记将您包含的Javascript文件从application.html.erb正文的结尾移至其<head>

如此处所述 ,如果您为了速度优化原因而将应用程序JavaScript链接放在页脚中,则需要将其移至标记中,以便在标记中的内容之前加载它。 这个解决方案为我工作。


 <%= link_to 'Edit', edit_article_path(article), 'data-no-turbolink' => true %>

也许你可以像这样使用“准备好”,就像关闭你的turbolink。


$(document).ready(ready)  

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




turbolinks