在点击任何页面链接时触发 JavaScript,但在页面内容加载之前

Hi.
When we change page in Discourse, these are the apparent steps:

  1. We click on the link
  2. The current content disappears and the loader appears
  3. The URL is updated and the new content appears

This is slightly different when we go from a page to the home, as the URL is changed to the home URL when the current content disappears, and not when the new content appears.

My goal is to have a script that is executed as soon as we click any page link on Discourse.
api.onPageChange won’t fit in this case since the code is executed quite at the same time the new page content is loaded.

Is there a Discourse method for that? I look at the event triggers but didn’t find any one corresponding to what I need.

1 个赞

Hey :wave:

There’s currently no method in the Plugin-API that will allow you to fire a script before a page transition because this has not come up before as far as I recall.

That said, you can leverage on the willTransition() action in the application route

You would use something that like this in your theme / component

// this fires after the transition
api.onPageChange((url, title) => {
  console.log("after transition");
});

// this fires right before the transition
api.modifyClass("route:application", {
  pluginId: "some-name",
  actions: {
    willTransition() {
      // run core code first
      this._super(...arguments);
      // then do some work
      console.log("before transition");
      // you can also do something like this to see what data you have
      // to work with like _router
      console.log(this)
    }
  }
});

6 个赞

Exactly what I needed. Thanks!

2 个赞

这似乎在从主题列表进入主题时不会触发?

我也尝试添加了一个:

      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 在所有情况下都不一定会在应用程序路由上触发。(例如,如果子路由有 willTransition 操作,它不一定会冒泡)

我建议改用 Ember 路由器服务上的事件:RouterService | 5.12.0 | Ember API Documentation
例如,类似这样的:

const router = api.container.lookup("service:router");
router.on("routeWillChange", () => {
  console.log("route will change 已触发");
});
2 个赞

太好了,谢谢你,David,我下次会试试!

这次调查(咳咳)是因为我需要一种在每次页面更改时触发某些操作的方法,而且是在渲染(Render)之前

Apparently,页面更改 API 事件似乎不能保证在页面元素渲染之前触发。

1 个赞

我认为您将很难完美地做到这一点。Ember 希望完全控制渲染,因此尝试挂钩到任意点将很困难,并且可能会导致问题(取决于您要尝试做什么)。

显然,我不知道您的最终目标是什么……所以也许这种痛苦是值得的。如果是这样:请随时忽略我 :wink:

(当然,如果您想就您试图解决的问题开设一个 Dev 主题,我很乐意看看)

很高兴能明确说明,因为代码是开源的:

我正在与第三方广告提供商合作,他们有一个 JavaScript 中的广告页面重置函数,需要在触发新页面的广告之前运行。

任何改进都受欢迎,并且我已经通过 Johani 的代码在主题列表中实现了这一点。(在一个开放的 PR 中)。

但这遗留了主题……我接下来会尝试你的建议,如果能进一步改进,我将在两个实例中都采用它。

我明白了,所以你不是直接修改 DOM :ok_hand:

那样的话,我希望 routeWillChange 会起作用——它应该在下一个路由渲染之前触发。

需要注意的是……在重定向的情况下,它可能会触发两次。或者触发后,但转换最终被中止了。但也许在这种情况下是可以的。

2 个赞

是的,在 Merefield Technology Towers 这里没有任何不好的直接 DOM 修改的胡闹。:sweat_smile:

是的,我会使用该服务,它的用途就是如此!我会反馈我的经验,因为我相信结果可能会让其他人感兴趣。

3 个赞

是的,这样就清理干净了,现在两条路线上的事情都按正确的顺序进行了。

:rocket:

感谢您的帮助!

2 个赞