Rails 4: как использовать $(document).ready() с турбо-ссылками
Я столкнулся с проблемой в своем приложении на Rails 4, пытаясь организовать файлы JS "по пути рельсов". Ранее они были разбросаны по разным взглядам. Я организовал их в отдельные файлы и скомпилировал их с конвейером ресурсов. Тем не менее, я только что узнал, что "готовое" событие jQuery не срабатывает при последующих щелчках, когда включена турбо-ссылка. При первой загрузке страницы это работает. Но когда вы нажимаете на ссылку, что-нибудь внутри ready( function($) {
не будет выполнен (потому что страница фактически не загружается снова). Хорошее объяснение: здесь.
Поэтому мой вопрос: как правильно обеспечить правильную работу событий jQuery при включенных турбо-ссылках? Вы оборачиваете сценарии в специфичный для Rails слушатель? Или, возможно, у рельсов есть какая-то магия, которая делает это ненужным? Документы немного расплывчаты о том, как это должно работать, особенно в отношении загрузки нескольких файлов через манифест (ы), такие как application.js.
21 ответ
Я только что узнал о другом варианте решения этой проблемы. Если вы загрузите jquery-turbolinks
жемчужина это будет связывать события Rails Turbolinks с document.ready
события, так что вы можете написать свой JQuery обычным способом. Вы просто добавляете jquery.turbolinks
сразу после jquery
в файле манифеста js (по умолчанию: application.js
).
Вот что я делаю... CoffeeScript:
ready = ->
...your coffeescript goes here...
$(document).ready(ready)
$(document).on('page:load', ready)
последняя строка прослушивает загрузку страницы, которая будет вызывать турбо-ссылки.
Редактировать... добавление версии 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...
});
Недавно я нашел самый простой и понятный способ борьбы с ним:
$(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
событие.
Обнаружил это в документации по Rails 4, аналогично решению DemoZluk, но немного короче:
$(document).on 'page:change', ->
# Actions to do
ИЛИ ЖЕ
$(document).on('page:change', function () {
// Actions to do
});
Если у вас есть внешние скрипты, которые вызывают $(document).ready()
или если вы не можете быть обеспокоены переписыванием всего существующего JavaScript, то этот драгоценный камень позволяет вам продолжать использовать $(document).ready()
с TurboLinks: https://github.com/kossnocorp/jquery.turbolinks
Согласно новым направляющим рельсов, правильный путь заключается в следующем:
$(document).on('turbolinks:load', function() {
console.log('(document).turbolinks:load')
});
или, в coffeescript:
$(document).on "turbolinks:load", ->
alert "page has loaded!"
Не слушай событие $(document).ready
и только одно событие будет запущено. Никаких сюрпризов, нет необходимости использовать драгоценный камень jquery.turbolinks.
Это работает с рельсами 4.2 и выше, а не только с рельсами 5.
ПРИМЕЧАНИЕ. См. Ответ @SDP, чтобы узнать о чистом встроенном решении.
Я исправил это следующим образом:
убедитесь, что вы включили application.js до включения других зависимых от приложения 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');
});
Ничто из вышеперечисленного не работает для меня, я решил это, не используя jQuery $(document).ready, а вместо этого использовал addEventListener.
document.addEventListener("turbolinks:load", function() {
// do something
});
$(document).on 'ready turbolinks:load', ->
console.log '(document).turbolinks:load'
Вы должны использовать:
document.addEventListener("turbolinks:load", function() {
// your code here
})
Либо использовать
$(document).on "page:load", attachRatingHandler
или используйте функцию.on в jQuery для достижения того же эффекта
$(document).on 'click', 'span.star', attachRatingHandler
смотрите здесь для получения более подробной информации: http://srbiv.github.io/2013/04/06/rails-4-my-first-run-in-with-turbolinks.html
Я нашел следующую статью, которая отлично работает для меня, и подробно описывает использование следующего:
var load_this_javascript = function() {
// do some things
}
$(document).ready(load_this_javascript)
$(window).bind('page:change', load_this_javascript)
Вместо того, чтобы использовать переменную для сохранения "готовой" функции и привязки ее к событиям, вы можете вызвать ready
событие всякий раз, когда page:load
триггеры.
$(document).on('page:load', function() {
$(document).trigger('ready');
});
$(document).ready(ready)
$(document).on('turbolinks:load', ready)
Я подумал, что оставлю это здесь для тех, кто обновляет Turbolinks 5: самый простой способ исправить ваш код - это перейти из:
var ready;
ready = function() {
// Your JS here
}
$(document).ready(ready);
$(document).on('page:load', ready)
чтобы:
var ready;
ready = function() {
// Your JS here
}
$(document).on('turbolinks:load', ready);
Вот что я сделал для того, чтобы вещи не выполнялись дважды:
$(document).on("page:change", function() {
// ... init things, just do not bind events ...
$(document).off("page:change");
});
Я использую jquery-turbolinks
драгоценный камень или сочетание $(document).ready
а также $(document).on("page:load")
или используя $(document).on("page:change")
Сам по себе ведет себя неожиданно - особенно если вы в разработке.
Обновить Turbolinks -> Hotwired Turbo (2021+)
Turbolinks был заархивирован и теперь поддерживается как часть подключенного к турбо.
Если вы используете новую версию, вы можете слушать турбо-загрузку следующим образом:
document.documentElement.addEventListener("turbo:load", (e) {
console.log("turbo:load", e)
});
Вот полный список событий, которые они транслируют в элементе документа:
-
turbo:click
-
turbo:before-visit
-
turbo:visit
-
turbo:submit-start
-
turbo:before-fetch-request
-
turbo:before-fetch-response
-
turbo:submit-end
-
turbo:before-cache
-
turbo:before-render
-
turbo:before-stream-render
-
turbo:render
-
turbo:load
-
turbo:before-frame-render
-
turbo:frame-load
-
turbo:frame-render
-
turbo:frame-missing
-
turbo:fetch-request-error
Испытано так много решений, наконец, пришли к этому. Это много, ваш код определенно не вызывается дважды.
var has_loaded=false;
var ready = function() {
if(!has_loaded){
has_loaded=true;
// YOURJS here
}
}
$(document).ready(ready);
$(document).bind('page:change', ready);
Я обычно делаю следующее для своих проектов:
В application.js
function onInit(callback){
$(document).ready(callback);
$(document).on('page:load', callback);
}
Затем в остальных файлах.js вместо использования $(function (){})
Я звоню onInit(function(){})
<%= link_to 'Edit', edit_article_path(article), 'data-no-turbolink' => true %>
может быть, вы можете использовать это, чтобы использовать "готово", это так же, как закрыть вашу турболинку.
Сначала установите jquery-turbolinks
драгоценный камень. И затем, не забудьте переместить ваши включенные файлы Javascript с конца тела вашего application.html.erb
к его <head>
,
Как описано здесь, если вы поместили ссылку javascript приложения в нижний колонтитул в целях оптимизации скорости, вам нужно будет переместить его в тег, чтобы он загружался до содержимого в теге. Это решение сработало для меня.
Я обнаружил, что мои функции удваиваются при использовании функции для ready
а также turbolinks: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);
};
Таким образом, ваши функции не удваиваются, если поддерживаются турболинки!