Запускать JavaScript при клике на любую ссылку на странице, но до загрузки её содержимого?

Привет.
Когда мы переходим на другую страницу в Discourse, видимые шаги следующие:

  1. Мы кликаем по ссылке.
  2. Текущее содержимое исчезает, и появляется индикатор загрузки.
  3. URL обновляется, и появляется новое содержимое.

Это немного отличается при переходе на главную страницу: URL меняется на адрес главной страницы, когда текущее содержимое исчезает, а не когда появляется новое.

Моя цель — запустить скрипт сразу после клика по любой ссылке на странице в Discourse.
api.onPageChange не подходит в данном случае, так как код выполняется примерно в то же время, когда загружается содержимое новой страницы.

Есть ли в Discourse метод для этого? Я изучил триггеры событий, но не нашёл ни одного, который соответствовал бы моим требованиям.

Привет :wave:

На данный момент в Plugin-API нет метода, который позволял бы запускать скрипт перед переходом между страницами, поскольку, насколько я помню, такой потребности ранее не возникало.

Тем не менее, вы можете использовать действие willTransition() в маршруте приложения:

В вашей теме или компоненте вы можете использовать что-то вроде этого:

// это срабатывает после перехода
api.onPageChange((url, title) => {
  console.log("after transition");
});

// это срабатывает непосредственно перед переходом
api.modifyClass("route:application", {
  pluginId: "some-name",
  actions: {
    willTransition() {
      // сначала выполняем основной код
      this._super(...arguments);
      // затем выполняем дополнительную работу
      console.log("before transition");
      // вы также можете сделать что-то подобное, чтобы увидеть, какие данные доступны
      // для работы, например _router
      console.log(this)
    }
  }
});

Вот именно то, что мне было нужно. Спасибо!

Похоже, это не срабатывает при переходе к теме из списка тем?

Я также пробовал добавить следующее:

      api.modifyClass("route:topic", {
        pluginId: PLUGIN_ID,
        actions: {
          willTransition() {

но это тоже не срабатывает.

Вот несколько причин, по которым это может не работать:

  1. Использование действий в хеши — это устаревший синтаксис, который больше не применяется в Discourse. Теоретически это должно работать, но совместимость с новым синтаксисом может быть неидеальной. Современный способ выглядит так:

    api.modifyClass("route:application", (Superclass) => class extends Superclass {
      @action
      willTransition(){
        console.log("выполнить что-то");
        super.willTransition(...arguments);
      }
    });
    

    Стандартное предупреждение о modifyClass остаётся в силе: это рискованно и может сломаться в любой момент.

  2. Я не думаю, что willTransition гарантированно срабатывает на маршруте application во всех ситуациях. (Например, если у дочернего маршрута есть действие willTransition, оно не обязательно будет всплывать вверх).

Рекомендую использовать события сервиса маршрутизатора Ember вместо этого: RouterService | 5.12.0 | Ember API Documentation

Например, что-то вроде:

const router = api.container.lookup("service:router");
router.on("routeWillChange", () => {
  console.log("событие routeWillChange сработало");
});

Отлично, спасибо, Дэвид, я попробую это в следующий раз!

Это расследование было инициировано (хм), потому что мне нужен был способ запускать что-то при каждом изменении страницы и до рендеринга.

Событие API изменения страницы, похоже, не гарантируется срабатывание до рендеринга элементов страницы, судя по всему.

Думаю, вам будет сложно сделать это идеально. Ember предполагает полный контроль над рендерингом, поэтому попытка встроиться в произвольные точки будет сложной и может вызвать проблемы (в зависимости от того, что вы пытаетесь сделать).

Очевидно, я не знаю вашу конечную цель… поэтому, возможно, такие трудности оправданы. В таком случае: не стесняйтесь игнорировать меня :wink:

(конечно, если вы захотите открыть тему в Development о проблеме, которую пытаетесь решить, я с радостью посмотрю)

Рад быть конкретным, так как код является открытым:

Я работаю с сторонним рекламным провайдером, и у них есть функция сброса рекламной страницы на JavaScript, которую необходимо выполнить перед запуском рекламы на новой странице.

Любые улучшения будут приветствоваться. Я уже реализовал это в списке тем с помощью кода Johani (в открытом PR).

Однако это оставило тему… Я попробую ваше предложение дальше и внедрю его в обоих случаях, если это ещё больше улучшит ситуацию.

А, понятно, значит, вы не изменяете DOM напрямую :ok_hand:

В таком случае надеюсь, что routeWillChange сработает — он определённо должен сработать до рендеринга следующего маршрута.

Однако есть нюанс: в случае перенаправлений он может сработать дважды. Или сработать, а затем переход будет отменён. Но, возможно, в данном случае это не проблема.

Да, здесь, в башне технологий Merefield, никаких подобных шалостей с прямым изменением DOM. :sweat_smile:

Да, я воспользуюсь сервисом, для этого он и создан! Я вернусь с отзывом о своём опыте, так как, уверен, результаты могут заинтересовать других.

Да, теперь всё очищается, и события происходят в правильном порядке на обоих маршрутах.

:rocket:

Спасибо за помощь!