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如何运作; 皮特亨特