Rails 4: как использовать $ (document) .ready () с турбо-ссылками

403

Я столкнулся с проблемой в своем Rails 4 при попытке организовать JS файлы "путь рельсов". Раньше они были разбросаны по разным взглядам. Я организовал их в отдельные файлы и скомпилировал их с помощью конвейера активов. Тем не менее, я только что узнал, что событие jQuery "ready" не срабатывает при последующих нажатиях, когда включено турбосвязывание. При первой загрузке страницы она работает. Но когда вы нажимаете ссылку, что-либо внутри ready( function($) { не будет выполнено (потому что страница на самом деле не загружается снова). Хорошее объяснение: здесь.

Итак, мой вопрос: какой правильный способ обеспечить правильное функционирование jQuery-событий во время включения турбо-ссылок? Вы завершаете скрипты в Rails-специфическом слушателе? Или, может быть, у рельсов есть какая-то магия, которая делает это ненужным? Документы немного расплывчаты в отношении того, как это должно работать, особенно в отношении загрузки нескольких файлов через манифест (ы), например application.js.

Теги:
ruby-on-rails-4
asset-pipeline
turbolinks

19 ответов

222
Лучший ответ

Я только что узнал о другом варианте решения этой проблемы. Если вы загрузите драгоценный камень jquery-turbolinks, он привяжет события Rails Turbolinks к событиям document.ready, чтобы вы могли написать свой jQuery обычным способом. Вы просто добавляете jquery.turbolinks сразу после jquery в файл манифеста js (по умолчанию: application.js).

  • 2
    Круто, спасибо! Именно то, что мне нужно. Рельсы путь. Конвенция.
  • 6
    Согласно документации , вы должны добавить //= require jquery.turbolinks в манифест (например, application.js).
Показать ещё 14 комментариев
564

Вот что я делаю... 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...

});
  • 3
    Это сценарий кофе? Я еще не изучил это. Есть ли js или jQuery, эквивалентный вашему примеру?
  • 6
    Думаю , я получил его: var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready) Есть ли забота как .ready и 'page:load' сработала?
Показать ещё 17 комментариев
196

Недавно я нашел самый чистый и понятный способ борьбы с ним:

$(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.

  • 9
    Это намного проще, чем принятый ответ о создании отдельной функции ready() . Дополнительные бонусы за объяснение привязки делегированных событий за пределами функции ready .
  • 1
    Недостатком этого метода является то, что $(document).on( "ready", handler ), deprecated as of jQuery 1.8. JQuery / готовый
Показать ещё 3 комментария
90

Обнаружено это в документации 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

76

В соответствии с новыми направляющими rails правильный способ заключается в следующем:

$(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.

  • 0
    здорово, это сработало для меня. Пробное решение здесь: stackoverflow.com/questions/17881384/… но по какой-то причине не сработало. Теперь я загружаю на турболинки: загружаю вместо
  • 0
    Да, это правильное решение. Все остальные ответы старые
Показать ещё 7 комментариев
10

ПРИМЕЧАНИЕ. См. ответ @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');
});
  • 2
    Это кажется самым чистым, поскольку вам нужно добавить это только в одном месте, а не в каждом файле coffeescript. Хорошо сделано!
  • 0
    @sled Так значит ли это использование метода SDP с использованием гема и этого кода? Или это ответ, который не использует драгоценный камень?
Показать ещё 4 комментария
8

Ничего из этого не работает для меня, я решил это, не используя jQuery $(document).ready, но вместо этого используйте addEventListener.

document.addEventListener("turbolinks:load", function() {
  // do something
});
3

Либо используйте

$(document).on "page:load", attachRatingHandler

или использовать функцию jQuery.on для достижения того же эффекта

$(document).on 'click', 'span.star', attachRatingHandler

см. здесь для более подробной информации: http://srbiv.github.io/2013/04/06/rails-4-my-first-run-in-with-turbolinks.html

2
$(document).on 'ready turbolinks:load', ->
  console.log '(document).turbolinks:load'
  • 0
    Это единственное решение, которое работает для меня в каждом браузере, для Turbolinks> = 5 и срабатывает как при загрузке первой страницы, так и при нажатии на любые ссылки (с турболинками). Это происходит потому, что хотя Chrome запускает turbolinks:load при первой загрузке страницы, Safari - нет, и хакерский способ исправить это (запуск turbolinks:load в application.js ), очевидно, ломает Chrome (который срабатывает дважды при этом). Это правильный ответ. Обязательно идите с 2 событиями ready и turbolinks:load .
2

Вы должны использовать:

document.addEventListener("turbolinks:load", function() {
  // your code here
})

из turbolinks doc.

2

Я решил, что оставлю это здесь для тех, кто обновляется до 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#issuecomment-184717346

2

Я нашел следующую статью которая отлично поработала для меня и подробно описывает следующее:

var load_this_javascript = function() { 
  // do some things 
}
$(document).ready(load_this_javascript)
$(window).bind('page:change', load_this_javascript)
2

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

$(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") самостоятельно ведет себя неожиданно - особенно если вы находитесь в разработке.

  • 0
    Не могли бы вы объяснить, что вы подразумеваете под поведением неожиданно?
  • 0
    Если у меня есть просто простое предупреждение без бита $(document).off в этой анонимной функции «page: change» выше, оно, очевидно, предупредит, когда я доберусь до этой страницы. Но, по крайней мере, при разработке под управлением WEBrick, он также будет предупреждать, когда я нажимаю ссылку на другую страницу. Событие хуже, оно предупреждает дважды, когда я затем нажимаю ссылку на исходную страницу.
2

Вместо использования переменной для сохранения "готовой" функции и привязки ее к событиям вы можете запускать событие ready при срабатывании page:load.

$(document).on('page:load', function() {
  $(document).trigger('ready');
});
1
$(document).ready(ready)  

$(document).on('turbolinks:load', ready)
  • 2
    Хотя этот фрагмент кода может решить вопрос, в том числе объяснение действительно помогает улучшить качество вашего сообщения. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причин, по которым вы предлагаете код.
  • 3
    На самом деле, этот ответ неверен. turbolinks:load события turbolinks:load для начальной загрузки страницы, так и после следующих ссылок. Если вы присоедините событие как к стандартному событию ready и к turbolinks:load , оно будет срабатывать дважды при первом посещении страницы.
Показать ещё 2 комментария
0

Я обычно делаю следующие для моих рельсов 4 проекта:

В application.js

function onInit(callback){
    $(document).ready(callback);
    $(document).on('page:load', callback);
}

Затем в остальных.js файлах вместо использования $(function(){}) я вызываю onInit(function(){})

0

Протестировано так много решений, наконец, дошло до этого. Этот код не обязательно дважды вызывается.

      var has_loaded=false;
      var ready = function() {
        if(!has_loaded){
          has_loaded=true;
           
          // YOURJS here
        }
      }

      $(document).ready(ready);
      $(document).bind('page:change', ready);
0

Сначала установите jquery-turbolinks gem. И затем, не забудьте переместить ваши включенные файлы Javascript из конца тела вашего application.html.erb в его <head>.

Как описанный здесь, если вы поместили ссылку javascript приложения в нижний колонтитул для оптимизации скорости, вам нужно будет переместить ее в чтобы он загружался до содержимого в теге. Это решение сработало для меня.

0
 <%= link_to 'Edit', edit_article_path(article), 'data-no-turbolink' => true %>

Может быть, вы можете использовать это, чтобы использовать "готово", это точно так же, как закрыть турболинк.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню