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

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

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


person emersonthis    schedule 12.09.2013    source источник


Ответы (19)


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

});
person Meltemi    schedule 12.09.2013
comment
Это сценарий кофе? Я еще этому не научился. Есть ли в вашем примере эквивалент js или jQuery? - person emersonthis; 12.09.2013
comment
Думаю, я понял: var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready) Есть ли опасения по поводу срабатывания обоих .ready и 'page:load'? - person emersonthis; 12.09.2013
comment
@Emerson есть очень полезный веб-сайт с явным названием: js2coffee.org - person MrYoshiji; 12.09.2013
comment
@MrYoshiji Спасибо. Я просто смотрел на это. Я до сих пор не совсем понимаю, что такое coffeescript, но он выглядит довольно прямолинейно, поэтому я попробую. - person emersonthis; 12.09.2013
comment
1. В чем разница между использованием page: load и page: change 2. В чем разница между использованием $ (document) .on и $ (document) .bind? - person Andreas; 31.10.2013
comment
Одна из проблем этого подхода заключается в том, что функция ready будет вызываться дважды. - person James McMahon; 04.12.2013
comment
разве он не вызывается только тогда, когда это необходимо? Он вызывает его, когда документ готов, а затем он вызывает его, когда страница загружается (что, как мы предполагаем, произошло от триггера турбо-ссылки). Верно? - person Jake Smith; 28.02.2014
comment
Я могу подтвердить, что функция ready не вызывается дважды. Если это жесткое обновление, запускается только событие ready. Если это турболинка, запускается только событие page:load. Невозможно одновременно запустить ready и page:load на одной странице. - person Christian; 14.03.2014
comment
Посмотрите на ответ SDP на его собственный вопрос, это правильный способ сделать это. Это будет работать, но это не лучший способ. - person Marcus; 17.04.2014
comment
Событие page:change, похоже, работает как для жесткого обновления, так и для загрузки турболыков. Кто-нибудь знает обратную сторону использования этого вместо ready и page:load? Единственное, о чем я могу думать, это то, что page:change является более ранним событием, поэтому DOM может не загружаться полностью при запуске вашего кода. Хотя не уверен. - person gabe; 30.05.2014
comment
Это можно сократить до $(document).on('ready page:load', ready), не так ли? - person cadlac; 04.08.2014
comment
FYI Вы также можете применить это для нескольких событий page:load и ready, включив строку, разделенную пробелами, для первого аргумента. $(document).on('page:load ready', ready); Второй аргумент - это просто функция, получившая имя ready в соответствии с примером этого ответа. - person ahnbizcad; 18.08.2014
comment
$(document).on('page:load ready', ready);' - это путь - person hwatkins; 29.01.2015
comment
$(document).on('page:load', functionName); определенно лучший способ. Работает с javaScript и jQuery - person samuelkobe; 11.02.2015
comment
Это решение не работало для меня в Rails 4.1. Прокрутите вниз, чтобы найти решение с jquery.turbolinks, которое работает. - person Dmitri Lihhatsov; 24.11.2015
comment
Это ДЕЙСТВИТЕЛЬНО работает для меня в Rails 4.2.6 - может быть, это не обязательно должен быть Rails 5? - person Ben Wheeler; 30.07.2016
comment
Для Rails 4.2.7 и Turbolinks 5 похоже, что турболинки будут перехватывать page:load и запускать только turbolinks:load. У меня работает, когда я слушаю последнее, а не первое. Но Chrome подтвердил, что браузер действительно запускал page:load - person sameers; 02.08.2016
comment
$(document).ready(ready) $(document).on('page:load', ready) дважды стрелял по мне. $(document).on('page:load ready', ready) работает так, как я ожидал. - person RobotEyes; 13.08.2016
comment
Если у вас есть код, вызываемый ready и turbolinks:load, он будет вызываться дважды. Это логично, потому что если код, выполняемый после события turbolinks:load, вызывается, это означает, что он обязательно прошел через событие ready. Если вы хотите, чтобы ваш код работал на странице без турболыков и на странице с, вам нужно поместить свой код в функцию, а затем сделать что-то вроде if (typeof Turbolinks === 'undefined') { $(document).ready(yourFunction); } else { $(document).on('turbolinks:load', yourFunction) }. Таким образом, ваш код будет правильно выполняться в представлении с турболинками и без них. - person escanxr; 05.09.2019

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

person emersonthis    schedule 16.09.2013
comment
Отлично, спасибо! Именно то, что мне нужно. Путь рельсов. Соглашение. - person Jeremy Becker; 15.12.2013
comment
Согласно документации, вы должны добавить //= require jquery.turbolinks в манифест (например, application.js). - person apocryphalauthor; 28.12.2013
comment
Ваш ответ, смешанный с ответом Мельтеми, - идеальное решение - person wildmonkey; 10.06.2014
comment
Очень чисто и полезно, особенно если вы интегрировали какую-то стороннюю тему вместе с ее файлами js. Спасибо! - person Bongs; 06.08.2014
comment
@wildmonkey два ответа исключают друг друга. 0.o - person ahnbizcad; 18.08.2014
comment
спасибо @gwho Я забыл обновить свой комментарий несколько месяцев назад, когда у меня возникла эта проблема. Ты прав! - person wildmonkey; 18.08.2014
comment
Этот драгоценный камень, похоже, не работает с вызовами AJAX. Как бы Вы это сделали? - person ahnbizcad; 20.02.2015
comment
Это правильный ответ. Добавление gem jquery-turbolinks помогло мне с этой проблемой. - person Francisco Quintero; 10.05.2015
comment
Когда вы добавляете этот драгоценный камень, вам необходимо перезапустить сервер рельсов - person Toby 1 Kenobi; 27.07.2015
comment
У меня все еще возникают проблемы с правильной работой турболинкса с помощью select2. - person Batman; 20.08.2015
comment
У меня это почему-то все еще не работает. Я добавил его в свой гем-файл, я установил его в комплекте. Я добавил // = requre jquery.turbolinks в application.js. Что-то мне не хватает? - person dcheng; 12.06.2016
comment
Обратите внимание, что Rails 4 теперь по умолчанию использует Turbolinks 5, который, в свою очередь, не поддерживается jquery.turbolinks! См. github.com/kossnocorp/jquery.turbolinks/issues/56. - person sebastian; 05.07.2016
comment
@sebastian - спасибо за это важное разъяснение. Итак, на данный момент лучшим решением было бы удалить турболинки из приложения. - person JosephK; 07.10.2016
comment
@Anwar - я полностью удалил его из Rails, чтобы избежать проблем с js, которые во многих случаях не работают. - person JosephK; 13.06.2017

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

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

person Artyom Tsoy    schedule 07.11.2013
comment
Это намного проще, чем принятый ответ о создании отдельной ready() функции. Бонусные голоса за объяснение привязки делегированных событий вне функции ready. - person Christian; 14.03.2014
comment
Недостатком этого метода является то, что $(document).on( "ready", handler ), deprecated as of jQuery 1.8. jquery / ready - person mfazekas; 12.08.2014
comment
@Dezi @mfazekas Будет ли это решение работать, если вы используете более ранние версии jQuery и БЕЗ гема jquery-turbolinks? Или часть ready сделана недействительной BY с помощью драгоценного камня? - person ahnbizcad; 18.08.2014
comment
Самый простой и легкий способ это сделать. Он поддерживает js-код, распределенный в нескольких файлах, и мне не нужно беспокоиться о том, в каком порядке они были включены. Намного чище, чем присвоение переменной. - person Evgeniya Manolova; 30.03.2015
comment
Вероятно, вам следует использовать page: change вместо page: load, поскольку первый запускается независимо от того, загружена ли страница с сервера или из кеша на стороне клиента. - person Nathan Long; 28.04.2015

Нашел это в документации Rails 4, похожей на решение DemoZluk, но немного короче:

$(document).on 'page:change', ->
  # Actions to do

OR

$(document).on('page:change', function () {
  // Actions to do
});

Если у вас есть внешние скрипты, которые вызывают $(document).ready(), или если вы не беспокоитесь о переписывании всего существующего JavaScript, то этот гем позволяет вам продолжать использовать $(document).ready() с TurboLinks: https://github.com/kossnocorp/jquery.turbolinks

person migu    schedule 03.02.2014

Согласно новым руководствам по рельсам, правильный способ - это сделать следующее:

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

person vedant    schedule 19.07.2016
comment
хорошо, это сработало для меня. Пробное решение здесь: stackoverflow.com/questions/17881384/, но по какой-то причине не сработало. Теперь я загружаю турболинки: вместо этого загружаю - person krinker; 03.08.2016
comment
Да, это правильное решение. Все остальные ответы старые - person vedant; 04.08.2016
comment
Может ли кто-нибудь подтвердить, что событие "turbolinks:load" работает в Rails 4.2? Префикс события turbolinks: был введен в New Turbolinks и не используется в Rails 4.2 IIRC, который использует Turbolinks Classic. Попробуйте "page:change", если "turbolinks:load" не работает в вашем приложении до Rails 5. См. guides.rubyonrails.org/v4.2.7/ - person Eliot Sykes; 07.08.2016
comment
@EliotSykes Руководство не обновлялось. Rails 4.2 теперь использует github.com/turbolinks/turbolinks вместо turbolinks-classic. И в любом случае это зависит от того, что вы указали в своем Gemfile. Надеюсь, вы скоро подтвердите то же самое :) - person vedant; 08.08.2016
comment
Спасибо @ vedant1811. На момент написания я подтверждаю, что новое приложение Rails 4.2.7 использует Turbolinks 5 (а не классику turbolinks). Разработчики читают это - проверьте свой Gemfile.lock на предмет используемой версии turbolinks. Если оно меньше 5.0, используйте page:change или обновите турболинки. Также обнаружено, что это может быть актуально для некоторых, где turbolinks переводит события в старые имена событий: github.com/turbolinks/turbolinks/blob/v5.0.0/src/turbolinks/ - person Eliot Sykes; 08.08.2016
comment
Отлично работает! Использование рельсов 5 - person Akash Agarwal; 23.10.2016
comment
Нужно ли делать alert "page has loaded!" отступ, чтобы функция обратного вызова действительно запускала его? - person mbigras; 13.02.2017
comment
@mbigras: Нет. Вы можете положить туда что угодно, и оно запустится. - person vedant; 14.02.2017
comment
@EliotSykes Я использую rails 4.2.8, и все работает! Спасибо - person Anwar; 13.05.2017

ПРИМЕЧАНИЕ. См. ответ @ 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');
});
person sled    schedule 28.10.2013
comment
Это кажется самым чистым, поскольку вам нужно добавить это только в одном месте, а не в каждый файл coffeescript. Хорошая работа! - person pyrospade; 31.10.2013
comment
@sled Так это говорит об использовании метода SDP для использования драгоценного камня и этого кода? Или это ответ, в котором не используется драгоценный камень? - person ahnbizcad; 18.08.2014
comment
забудьте этот ответ и используйте решение SDP. - person sled; 18.08.2014
comment
@sled Можно ли совместить решение SDP с идеей размещения вызова только в одном месте? - person ahnbizcad; 18.08.2014
comment
@gwho: Как показывает ответ SDP, turbolinks подключается к событию ready, это означает, что вы можете использовать стандартный способ инициализации: $(document).ready(function() { /* do your init here */});. Ваш код инициализации должен вызываться, когда загружается вся страница (- ›без турболинки), и ваш код инициализации должен выполняться снова, когда вы загружаете страницу через турболинки. Если вы хотите выполнить какой-то код ТОЛЬКО при использовании турболыка: $(document).on('page:load', function() { /* init only for turbolinks */}); - person sled; 18.08.2014
comment
@sled Понятно. Код инициализации - это просто код, который вы хотите выполнить. Поэтому я полагаю, что $(document).on('ready page:load ', function(){} ); не будет работать для ready, как описано в файле readme на github. - person ahnbizcad; 18.08.2014

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

document.addEventListener("turbolinks:load", function() {
  // do something
});
person RockL    schedule 13.09.2016

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

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

из документа turbolinks.

person Gian Franco Fioriello    schedule 18.06.2017

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

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

person derekyau    schedule 12.09.2013

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

$(document).on('page:load', function() {
  $(document).trigger('ready');
});
person wachunei    schedule 25.11.2014

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

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

person Gray Kemmey    schedule 19.03.2015
comment
Не могли бы вы объяснить, что вы имеете в виду под неожиданным поведением? - person sunnyrjuneja; 30.04.2015
comment
Если у меня есть простое предупреждение без бита $(document).off на этой анонимной странице: функция изменения выше, она, очевидно, будет предупреждать, когда я перейду на эту страницу. Но, по крайней мере, при разработке, использующей WEBrick, он также будет предупреждать, когда я нажимаю ссылку на другую страницу. Что еще хуже, он дважды предупреждает, когда я затем нажимаю ссылку на исходную страницу. - person Gray Kemmey; 13.05.2015

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

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

Я решил, что оставлю это здесь для тех, кто обновляется до Turbolinks 5: самый простой способ исправить код - перейти от:

var ready;
ready = function() {
  // Your JS here
}
$(document).ready(ready);
$(document).on('page:load', ready)

to:

var ready;
ready = function() {
  // Your JS here
}
$(document).on('turbolinks:load', ready);

Ссылка: https://github.com/turbolinks/turbolinks/issues/9#issuecomment-184717346

person tirdadc    schedule 01.07.2016

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

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

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

person Simon Meyborg    schedule 01.07.2016

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

In application.js

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

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

person muZk    schedule 16.02.2018

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

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

person Aboozar Rajabi    schedule 21.06.2016

Я обнаружил, что мои функции удваиваются при использовании функции для 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);
};

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

person Lee Eather    schedule 10.10.2019

person    schedule
comment
Это единственное решение, которое работает для меня во всех без исключения браузерах, для Turbolinks ›= 5 и которое срабатывает как при загрузке первой страницы, так и при нажатии любых ссылок (с turbolinks). Это так, потому что, хотя Chrome запускает turbolinks:load при загрузке самой первой страницы, Safari этого не делает, и хакерский способ исправить это (запуск turbolinks:load на application.js), очевидно, ломает Chrome (который запускается дважды с этим). Это правильный ответ. Определенно идите с двумя событиями ready и turbolinks:load. - person lucasarruda; 01.05.2018

person    schedule
comment
Хотя этот фрагмент кода может решить вопрос, включение объяснения действительно помогает улучшить качество вашего поста. Помните, что вы отвечаете на вопрос читателей в будущем, и эти люди могут не знать причины вашего предложения кода. - person andreas; 14.10.2016
comment
Собственно, это неверный ответ. Событие turbolinks:load срабатывает при начальной загрузке страницы, а также после перехода по ссылкам. Если вы прикрепите событие как к стандартному событию ready, так и к событию turbolinks:load, оно сработает дважды при первом посещении страницы. - person alexanderbird; 13.11.2016
comment
Это неверный ответ. Как сказал @alexanderbird, это заставляет ready запускаться дважды при последующих загрузках страницы. Пожалуйста, измените или удалите его. - person chester; 14.02.2017
comment
@alexanderbird Ваш комментарий решил для меня одну из проблем - person Anwar; 13.05.2017