Turbolinks и специфичные для контроллера активы
Я модифицировал application.html.erb
использовать определенные ресурсы контроллера:
application.html.erb
:
<!DOCTYPE html>
<html>
<head>
<title>My Application</title>
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %>
<%= stylesheet_link_tag params[:controller], 'data-turbolinks-track' => true %>
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %>
<%= javascript_include_tag params[:controller], 'data-turbolinks-track' => true %>
<%= csrf_meta_tags %>
</head>
<body>
... other html template ...
Проблема в том, что у меня установлены турболинки. Когда я перемещаюсь через тот же контроллер, турболинкс работает. Но когда я переключаюсь на другой контроллер, турболинки выполнят полную перезагрузку. Есть ли способ это исправить?
2 ответа
Turbolinks
Турболинкс берет <body>
вашей HTML-страницы, и изменяет его с помощью Ajax, оставляя <head>
Площадь нетронутой.
Это работает только если ваш <head>
останется прежним - иначе как его можно сохранить постоянным? Таким образом, в смысле изменения страницы / ресурсов вашего контроллера, вам придется пройти полное обновление страницы без Turbolinks (по крайней мере, если вы используете Turbolinks без взлома)
Я бы порекомендовал исправить это, изменив структуру активов вашего контроллера, в частности, чтобы сделать как можно меньше изменений в <head>
Площадь, насколько это возможно.
-
Отслеживание Turbolinks
После прочтения Turbolinks documentation
вы можете извлечь выгоду из удаления turbolinks-data-track
Опция из вашего контроллера конкретного имущества:
<%= javascript_include_tag controller_name, 'data-turbolinks-track' => false %>
Вы можете отслеживать определенные ресурсы, такие как application.js и application.css, которые, как вы хотите убедиться, всегда имеют последнюю версию в сеансе Turbolinks. Это делается путем маркировки этих ссылок ресурсов с помощью data-turbolinks-track, например:
<link href="/assets/application-9bd64a86adb3cd9ab3b16e9dca67a33a.css" rel="stylesheet" type="text/css" data-turbolinks-track>
Если эти ресурсы изменяют URL-адреса (для этого добавьте штамп md5), страница будет полностью перезагружена, а не будет проходить через Turbolinks. Это гарантирует, что все сеансы Turbolinks всегда будут работать на вашем последнем JavaScript и CSS.
-
Что-то, от чего вы выиграете, это использование controller_name
помощник (вместо params[:controller]
):
<%= javascript_include_tag 'application', controller_name, 'data-turbolinks-track' => true %>
Поместите js вашего контроллера в тег body. Так как turbolinks не будет касаться тела html, вы будете перезагружать этот фрагмент кода js при каждом посещении страницы.
В твоем случае
<body>
<%= javascript_include_tag params[:controller] %>
...
</body>
Но если у вас много кода на вашем контроллере js, вы можете заметить, что приведенное выше решение отнимает много времени. Потому что, когда вы посещаете страницу, этот большой кусок кода будет перезагружен. Так как с этим бороться?
■ Следующий метод может привести к тому, что некоторые события jquery будут связаны несколько раз. Это проблема турболинков. Прочитайте эту статью http://staal.io/blog/2013/01/18/dangers-of-turbolinks/
Более эффективное решение
По сути, когда пользователь впервые посещает ваш сайт, вы загружаете весь код js, следя за тем, чтобы не запускались специфичные для контроллера (оборачивая их в функции соответственно), и сохраняете их в глобальной переменной, скажем, Site
, Затем вы запускаете свой js для конкретного контроллера, записывая что-то вроде
<script>
$(document).on("ready page:load", function () {
Site.load('<%= controller_name %>');
}
</script>
в теле тега.
Таким образом, фактический 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
<body>
<script>
$(document).on("page:load", function () {
Site.load('<%= controller_name %>');
}
</script>
<%= yield %>
</body>
Как насчет кода 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
<body>
<script>
$(document).on("ready page:load", function () {
Site.load('<%= controller_name %>.<%= action_name %>');
}
</script>
<%= yield %>
</body>
связанные с
Вот интересное видео о загрузке javascript, css и других ресурсов для одностраничных приложений, которые вы можете посмотреть.
OSCON 2014: как работает Instagram.com; Пит Хант