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


422

Я зіткнувся з проблемою в моєму додатку Rails 4, намагаючись впорядкувати файли JS "в напрямку рейки". Раніше вони були розкидані по-різному. Я організував їх в окремі файли і склав їх із конвеєра активів. Однак я тільки що дізнався, що подія "готового" jQuery не спрацьовує при наступних клацаннях, коли ввімкнено турбозв'язку. Перший раз, коли ви завантажуєте сторінку, вона працює. Але при натисканні на посилання все, що знаходиться всередині ready( function($) {, не буде виконано (оскільки сторінка насправді не завантажується знову). Гарне пояснення: ось .

Отже, моє запитання: який правильний спосіб забезпечити належну роботу подій jQuery під час включення турбо-посилань? Чи ви загортаєте сценарії у слухача, орієнтованого на Rails? А може, у рейок є якась магія, яка робить її непотрібною? Документи трохи розпливчасті щодо того, як це має працювати, особливо стосовно завантаження декількох файлів через маніфест (и), такі як application.js.

Відповіді:


554

Ось що я роблю ... 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 еквівалент вашому прикладу?
emersonthis

6
Подумайте, я це зрозумів: var ready = function() { ... } $(document).ready(ready) $(document).on('page:load', ready)чи є занепокоєння обох .ready та 'page:load'спрацьовування?
emersonthis

4
@Emerson є дуже корисний веб-сайт із чіткою назвою: js2coffee.org
MrYoshiji

16
Я можу підтвердити, що готову функцію не викликають двічі. Якщо це важко оновити, тількиready подія. Якщо це навантаження turbolinks, тількиpage:load подія. Неможливо і для обох, readyі page:loadдля звільнення на одній сторінці.
Крістіан

7
FYI Ви також можете застосувати це для кількох подій page:loadі readyшляхом включення розділених прогалин рядки для першого argumet. $(document).on('page:load ready', ready);Другий аргумент - це просто функція, яку, можливо, іменують readyза прикладом цієї відповіді.
ahnbizcad

235

Я щойно дізнався про інший варіант вирішення цієї проблеми. Якщо ви завантажуєте на jquery-turbolinksдорогоцінний камінь буде пов'язувати події Rails Turbolinks до document.readyподій , так що ви можете написати JQuery звичайним способом. Ви просто додаєте jquery.turbolinksвідразу після цього jqueryу файл маніфесту js (за замовчуванням:) application.js.


2
Дивовижне, дякую! Саме те, що мені потрібно. Рейки шлях. Конвенція.
Джеремі Беккер

6
Згідно з документацією , ви повинні додати //= require jquery.turbolinksдо маніфесту (наприклад, application.js).
апокрифалатор

1
@wildmonkey дві відповіді взаємовиключні. 0.o
ahnbizcad

1
Коли ви додасте цей дорогоцінний камінь, вам потрібно перезапустити рейловий сервер
Toby 1 Kenobi

21
Зауважте, що Rails 4 тепер дефолт до Turbolinks 5, що, в свою чергу, не підтримується jquery.turbolinks! Дивіться github.com/kossnocorp/jquery.turbolinks/isissue/56
sebastian

201

Нещодавно я знайшов найбільш чистий і простий для розуміння спосіб поводження з ним:

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

АБО

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

EDIT
Якщо ви делегували події, прив’язані до 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 / ready
mfazekas

@Dezi @mfazekas Чи вирішило б це рішення, якщо ви використовуєте більш ранні версії jQuery і БЕЗ gem jquery-turbolinks? Або readyчастина зроблена недійсною BY за допомогою дорогоцінного каменю?
ahnbizcad

Найпростіший і найпростіший спосіб зробити це. Він підтримує js-код, розподілений у декількох файлах, і мені не потрібно турбуватися, в якому порядку вони були включені. Набагато чіткіше, ніж призначення змінної.
Євгенія Манолова

3
Ви, ймовірно, повинні використовувати "page: change" замість "page: load", оскільки попередня запускається, незалежно від завантаження сторінки з сервера або з кеша клієнта .
Натан Лонг

91

Виявлено це в документації на 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


79

Відповідно до нових напрямних рейок , правильний спосіб полягає в наступному:

$(document).on('turbolinks:load', function() {
   console.log('(document).turbolinks:load')
});

або, у кофескрипті:

$(document).on "turbolinks:load", ->
alert "page has loaded!"

Не слухайте події, $(document).readyі лише одна подія буде звільнена. Немає сюрпризів, не потрібно використовувати дорогоцінний камінь jquery.turbolinks .

Це працює з рейками 4.2 і вище, а не тільки з рельсами 5.


приємно, що це працювало для мене. Тут спробували рішення: stackoverflow.com/questions/17881384/…, але чомусь не вийшло. Зараз я завантажуюся на турболинки: замість цього завантажуюсь
krinker

1
Чи може хто-небудь підтвердити, що "turbolinks:load"подія працює в Rails 4.2? turbolinks:Приставка події була введена в Нью - Turbolinks і не використовується в Rails 4.2 IIRC , який використовує Turbolinks Класики . Спробуйте спробувати, "page:change"якщо "turbolinks:load"це не працює у вашій програмі попередньої Rails 5. Дивіться guides.rubyonrails.org/v4.2.7/…
Еліот Сайкс

1
@EliotSykes Посібник не оновлювався. Rails 4.2 тепер використовує github.com/turbolinks/turbolinks замість turbolinks-classic. І в будь-якому випадку, це залежить від того, що ви вказали у своєму Gemfile. Сподіваюсь, ви незабаром підтвердите те саме :)
продавець

3
Дякую @ vedant1811. На момент написання я підтверджую, що новий додаток Rails 4.2.7 використовує Turbolinks 5 (не турболинки-класичні). Розробники, які читають це - перевірте ваш Gemfile.lock на використану версію turbolinks. Якщо вона менше 5,0, то використовуйте page:changeабо оновіть турболинки. Також знайдене це може бути актуальним для деяких, де turbolinks переводить події до старих імен подій: github.com/turbolinks/turbolinks/blob/v5.0.0/src/turbolinks/…
Eliot Sykes

1
Чи alert "page has loaded!"потрібно відступити відступ, щоб реально виконувати функцію зворотного виклику?
mbigras

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. Хороша робота!
піроспада

@sled Отже, це приказка використовувати метод SDP з використанням дорогоцінного каміння та цього коду? Або це відповідь, яка не використовує дорогоцінний камінь?
ahnbizcad

забудьте цю відповідь і використовуйте рішення СДП.
сани

@sled Чи можна поєднати рішення SDP з поняттям про те, щоб подати дзвінок лише в одному місці?
ahnbizcad

1
@gwho: відповідь відображається як СДП, в turbolinks перехоплює до readyподії, це означає , що ви можете використовувати «стандартний» спосіб ініціалізації: $(document).ready(function() { /* do your init here */});. Ваш код init повинен викликатись, коли завантажується повна сторінка (-> без турболинок), а ваш код init повинен бути виконаний знову, коли ви завантажуєте сторінку через турболинки. Якщо ви хочете виконати якийсь код ТІЛЬКИ, коли використовується турболінка:$(document).on('page:load', function() { /* init only for turbolinks */});
сани

8

Жоден з перерахованих вище для мене не працює, я вирішив це, не використовуючи $ (документ) jQuery. Вже, але замість цього використовую addEventListener.

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

7
$(document).on 'ready turbolinks:load', ->
  console.log '(document).turbolinks:load'

Це єдине рішення, яке працює для мене в кожному браузері, для Turbolinks> = 5 і яке запускає як при завантаженні першої сторінки, так і при натисканні будь-яких посилань (з турболинками). Це так , тому що в той час як Chrome тригери turbolinks:loadна найпершої завантаження сторінки, Safari ні і Hacky спосіб виправити це (запуск turbolinks:loadна application.js) явно порушує Chrome (який стріляє двічі з цим). Це правильна відповідь. Однозначно йдіть з 2 подіями readyта turbolinks:load.
lucasarruda



2

Замість використання змінної для збереження функції "Ready" та прив'язування її до подій, ви, можливо, захочете запускати readyподію щоразу, коли page:loadтригери.

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

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")поводження з собою веде себе несподівано - особливо, якщо ти в розробці.


Ви не проти пояснити, що ви маєте на увазі під себе несподівано?
sunnyrjuneja

Якщо у мене є просто просте сповіщення без $(document).offшматочка в цій анонімній функції "сторінка: зміни" над ним, явно буде попереджено, коли я перейду на цю сторінку. Але принаймні в розробці, що працює під управлінням WEBrick, вона також буде попереджати, коли я натискаю посилання на іншу сторінку. Подія ще гірша, вона попереджає двічі, коли я натискаю посилання на початкову сторінку.
Сірий Кеммей

2

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

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

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/isissue/9#issuecomment-184717346


2
$(document).ready(ready)  

$(document).on('turbolinks:load', ready)

2
Хоча цей фрагмент коду може вирішити питання, зокрема пояснення дійсно допомагає покращити якість вашої публікації. Пам’ятайте, що ви відповідаєте на запитання читачів у майбутньому, і ці люди можуть не знати причини вашої пропозиції щодо коду.
andreas

4
Власне, ця відповідь невірна. В turbolinks:loadспрацьовує подія для початкового завантаження сторінки, а також після наступних посилань. Якщо ви приєднаєте подію до стандартної readyподії та turbolinks:loadподії, вона запуститься двічі під час першого відвідування сторінки.
alexanderbird

Ця відповідь невірна. Як сказав @alexanderbird, це призводить readyдо вистрілення двічі при наступних завантаженнях сторінки. Будь ласка, змініть або видаліть її.
честер

@alexanderbird Ваш коментар вирішив одну із проблем для мене
Anwar

1

Випробуваний стільки рішення нарешті дійшов до цього. Це багато вашого коду, безумовно, не називається двічі.

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

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


1

Зазвичай для своїх рейок я роблю наступне:

В application.js

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

Потім у решті файлів .js замість використання $(function (){})я дзвонюonInit(function(){})


0

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

Як описано тут , якщо ви з міркувань оптимізації швидкості помістили посилання javascript на додаток у нижньому колонтитулі, вам потрібно буде перемістити його в тег, щоб він завантажився перед вмістом у тезі. Це рішення спрацювало на мене.


0

Я виявив свої функції вдвічі, коли я використовував функцію, 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);
};

Таким чином ваші функції не подвоюються, якщо підтримуються турболинки!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.