Turbolinks和Controller特定的资产

我修改了application.html.erb以使用控制器特定资产:

application.html.erb

    My Application  true %>  true %>  true %>  true %>    ... other html template ... 

问题是,我安装了turbolinks。 当我在同一个控制器中导航时,turbolinks可以工作。 但当我切换到另一个控制器时,turbolinks将执行完全重新加载。 有没有什么办法解决这一问题?

Turbolinks

Turbolinks获取HTML页面的 ,并使用Ajax更改它,使区域保持不变。

这只适用于保持不变的情况 – 否则如何保持不变? 因此,在更改控制器页面/资产的意义上,您将不得不在没有Turbolinks的情况下进行整页更新(至少如果您使用Turbolinks而不进行黑客攻击)

我建议修复此问题的方法是更改​​特定于控制器的资产结构,特别是对区域进行尽可能少的更改。

Turbolinks跟踪

在阅读Turbolinks documentation ,您可以从控制器特定资产中删除turbolinks-data-track选项中受益:

 <%= javascript_include_tag controller_name, 'data-turbolinks-track' => false %> 

您可以跟踪某些资产,例如application.js和application.css,您希望确保这些资产始终是Turbolinks会话中的最新版本。 这是通过使用data-turbolinks-track标记这些资产链接来完成的,如下所示:

如果这些资产更改了URL(嵌入了md5标记以确保这一点),该页面将执行完全重新加载而不是通过Turbolinks。 这可确保所有Turbolinks会话始终使用最新的JavaScript和CSS。

CONTROLLER_NAME

您将从中受益的是使用controller_name帮助程序(代替params[:controller] ):

 <%= javascript_include_tag 'application', controller_name, 'data-turbolinks-track' => true %> 

将控制器特定的js放在body标签中。 由于turbolinks不会触及html主体,因此每次访问该页面时都会重新加载该段js代码。

在你的情况下

  <%= javascript_include_tag params[:controller] %> ...  

但是如果你的控制器js中有很多代码,你可能会注意到上面的解决方案很费时间。 因为当您访问该页面时,将重新加载该大块代码。 那么如何应对呢?


■以下方法可能导致某些jquery事件多次绑定。 这是turbolinks的问题。 阅读这篇文章http://staal.io/blog/2013/01/18/dangers-of-turbolinks/

更有效的解决方案

基本上,当用户首次访问您的站点时,您加载所有js代码,确保控制器特定的代码不会运行(分别将它们包装在函数中)并将它们保存在全局变量中,例如Site 。 然后通过编写类似的东西来触发特定于控制器的js

  

在身体标签。

这样,实际的控制器特定的js代码只加载一次并在需要时被触发。

履行

app/assets/javascripts/site.js

 var site; if(!window.Site) { site = window.Site = {}; site.controllers = {} site.load = function (controller) { if (this.controllers.hasOwnProperty(controller)) { this.controllers[controller].call(); } }; site.add = function (controller, fn) { this.controllers[controller] = fn; } } 

将控制器js包装在函数中并将它们保存到Site 。 例如, users.js

app/assets/javascripts/site.js

 Site.add("users", function () { // UserController related js code } 

在你的application.js中加载它们。

app/assets/javascripts/site.js

 //= require jquery //= require jquery_ujs //= require turbolinks //= require site //= require_tree . 

然后在您的布局中触发控制器特定的js。

app/views/layouts/application.html.erb

   <%= yield %>  

特定于动作的js代码怎么样?

只需修改site.js和布局即可。 我最后用以下片段结束了。

 (function (global) { var site; if(global.Site) { return; } site = global.Site = {}; site.controllers = {}; site.actions = {}; site.load = function (name) { var keys = name.split("."); var c = keys[0]; var cs = this.controllers; var as = this.actions; var i; if (cs.hasOwnProperty(c)) { for (i =0 ; i < cs[c].length; i++) { cs[c][i].call(); } } if (keys.length > 1 && as.hasOwnProperty(name)) { for (i =0 ; i < as[name].length; i++) { as[name][i].call(); } } }; site.add = function (name, fn) { var keys = name.split("."); var lv = keys.length > 1 ? this.actions : this.controllers; if (!lv.hasOwnProperty(name)) { lv[name] = [fn]; } else { lv[name].push(fn); } }; })(window); 

app/views/layouts/application.html.erb

   <%= yield %>  

有关

这是一个有趣的video,关于为您可能想要观看的单页应用加载javascript,css和其他资源。

OSCON 2014:Instagram.com如何运作; 皮特亨特

https://www.youtube.com/watch?v=VkTCL6Nqm6Y