置顶帖:新主题或已更新主题通知

是的,添加 URL 会导致导航,因为没有逻辑来拦截该事件。

该链接正在调用一个 Ember 操作。Discourse 中的所有操作都是可扩展的。因此,它们在某种程度上就像自定义钩子。那么如何修改一个操作呢?好吧,让我们先看看它做了什么。

在 Github 或本地搜索该操作的名称。操作总是定义在 JS 文件中,并在 Handlebars 中被引用。我们想查看定义,所以我们将搜索范围缩小到 JS 文件。

你得到了四个文件。你应该查看哪一个?你想要自定义

discovery/topics.hbs

模板。所以

discovery/topics.js

是你想要查看的文件。

这些代码有帮助吗?没有,但我们现在知道操作定义在哪里了。所以,让我们修改它。

discovery/topics.js 是一个 Ember 类。你可以使用插件 API 中的一种方法来修改 Ember 类,叫做… modifyClass :stuck_out_tongue:

https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L166-L195

我们已经知道想要修改的类了。它是 discovery/topics。我们需要知道它是什么类型的类。所以,让我们检查文件目录。

discourse/app/controllers/discovery/topics.js

它是一个控制器。

我们也知道想要修改该类中的 showInserted 操作。所以,我们从这里开始。

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
      // 让我们做一些工作
    }
  }
});

然后,你可以添加任何你想要的代码,以便当用户点击“新主题”横幅时滚动窗口。我使用了类似这样的代码。

const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();

你可以在这里阅读更多关于 scrollIntoView() 的内容。

然后,你像这样将其添加到 plugin-api 方法中。

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
+     const listControls = document.querySelector(".list-controls");
+     listControls.scrollIntoView();
    }
  }
});

那么,我们完成了吗?没有。这会破坏 Discourse,因为你完全覆盖了该操作。点击链接现在会滚动到 list-controls 元素,但不会加载新主题。为什么?因为核心中的代码不再被应用。我的意思是,这部分内容

那么,如何修复呢?用这一行简单的代码

this._super(...arguments);

如果你只是想添加功能,而不需要复制核心中的任何代码。先做你的工作,然后添加那一行。它的作用只是确保核心中的代码被应用。

api.modifyClass("controller:discovery/topics", {
  pluginId: 'sticky-new-topics-banner',
  actions: {
    showInserted() {
     const listControls = document.querySelector(".list-controls");
     listControls.scrollIntoView();
+
+    this._super(...arguments);
    }
  }
});

如果你测试这个,你会发现几乎所有东西都能很好地工作,除了… 标题与 list-controls 重叠了。为什么?因为标题被设置为 sticky。

你可以在 JS 中以多种方式修复这个问题——计算高度、获取偏移量、从 Discourse 导入辅助函数……等等。我不深入探讨这些。

最简单的方法是使用 CSS 和 scroll-margin-top,你可以在 这里 阅读相关内容。

所以,我们添加这个

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}

用英语来说:当链接被点击时,滚动到 list-controls 的顶部减去 2 倍的标题高度,这样就不会重叠,并且下方有一点空间。

那么,让我们把所有这些结合起来。

common header 标签页

<script type="text/discourse-plugin" version="0.8">
api.modifyClass("controller:discovery/topics", {
  pluginId: "sticky-new-topics-banner",
  actions: {
    showInserted() {
      const listControls = document.querySelector(".list-controls");
      listControls.scrollIntoView();
      this._super(...arguments);
    }
  }
});
</script>

common CSS

#list-area {
  // 移动端有不同的布局
  .alert-info,
  .show-more.has-topics {
    position: sticky;
    // Safari 有时没有前缀会很挑剔
    position: -webkit-sticky;
    top: var(--header-offset);
    // 横幅应该在内容之上
    z-index: z("header");
  }
}

.list-controls {
  scroll-margin-top: calc(var(--header-offset) * 2);
}
5 个赞