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);

Ссылка: https://github.com/turbolinks/turbolinks/issues/9

Вот что я сделал для того, чтобы вещи не выполнялись дважды:

$(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);
};

Таким образом, ваши функции не удваиваются, если поддерживаются турболинки!

Другие вопросы по тегам