Рефакторинг встроенных <script>элементов при использовании Turbolinks 5 - PullRequest
2 голосов
/ 15 марта 2019

Я перенес свое приложение в Ruby on Rails 5 (v5.2.2), и я пытаюсь использовать Turbolinks 5 (v5.2.0).

В моем приложении есть файлы для просмотра, которые включают <script>элементы, и я хотел бы заставить их работать должным образом с Turbolinks (чья документация указывает на избегать элементов скрипта и использовать событие turbolinks:load вместо ).Что я должен сделать?

То есть, например, у меня есть:

# app/views/.../_partial_template.html.erb
<script type="text/javascript">
  $(document).ready(function () { 
    $.ajax({...})
  });

  // Note: I tried to use $(document).on('turbolinks:load', function() {...});
  // and it seems that the JS code runs twice (or more) on every page load.
  // I also tried to use <script type="text/javascript" data-turbolinks-eval="false">...</script>
  // without success.
</script>

Как мне выполнить рефакторинг приведенного выше кода, чтобы он правильно работал с Turbolinks?


Бонус:

Документация Turbolinks гласит: Вы можете использовать встроенные сценарии тела для настройки постраничного состояния JavaScript или загрузки клиентских моделей .Что они имеют в виду под "состоянием JavaScript на странице" и "моделями клиентской загрузки"?

1 Ответ

1 голос
/ 15 марта 2019

Если ваши встроенные сценарии включены внизу <body> (или если они не сразу манипулируют DOM), то вы можете удалить свой код из функции $(document).ready… и заставить их работатькак и ожидалось.

Встроенные сценарии, как правило, не рекомендуется, поскольку традиционно они указывают, что код будет выполняться только на той странице, на которой он включен, и что любые прослушиватели событий будут автоматически уничтожены, когда пользователь уйдет.Однако в приложениях Turbolinks это не так.Если вы добавите прослушиватель событий во встроенный скрипт (и не удаляете его), он продолжит прослушивание и запуск при последующих загрузках страницы.Как вы выяснили, настроив прослушиватель событий turbolinks:load таким образом, обработчик сработал при последующих загрузках страниц и при повторном посещении первой страницы прослушиватель событий был добавлен снова, что привело к дублированию вызовов.

Относительнонастраивая «состояние JavaScript для каждой страницы» и «загрузочные модели на стороне клиента», скажем, у вас есть страница календаря, которую вы хотите улучшить с помощью некоторого JavaScript.Возможно, у вас есть Calendar класс JavaScript, который обрабатывает это, поэтому вы можете включить следующее, чтобы загрузить его с некоторым JSON:

<script>new Calendar(<%= @calendar.to_json %>)</script>

(имея в виду, что все добавленные прослушиватели событий настроены в Calender класс, вероятно, должен быть уничтожен в какой-то момент, например turbolinks:before-cache).

Это демонстрирует идею, но лучшим подходом в этом случае может быть установка системы, которая ищет элементы календаря, а затем в DOMсоздает ихНапример:

<div data-component="calendar" data-props="<%= @calendar.to_json %>">…</div>

затем в вашем JavaScript (входит в комплект приложения):

;(function () {
  var calendar

  $(document).on('turbolinks:load', function () {
    var $el = $('[data-component=calendar]')
    if ($el.length) calendar = new Calender($el.data('props'))
  })

  $(document).on('turbolinks:before-cache', function () {
    if (calendar) {
      calendar.destroy() // to teardown any event listeners etc
      calender = null
    }
  })
})()

Этот подход можно обобщить, и я рассмотрел одну реализацию здесь: https://stackoverflow.com/a/44057187/783009

Надеюсь, это поможет!

...