Discourse 包含数百个插件出口(Plugin Outlets),可用于在 Discourse UI 中注入新内容或替换现有内容。“出口参数”(Outlet arguments)可用于根据上下文自定义内容。
选择出口
要查找插件出口的名称,请在 Discourse 核心代码中搜索 “<PluginOutlet”,或使用 插件出口位置 主题组件。(例如 topic-above-posts)。
包装器出口
核心中的一些出口看起来像 <PluginOutlet @name="foo" />。这些出口允许您注入新内容。其他出口则会以如下方式“包装”现有的核心实现:
<PluginOutlet @name="foo">
核心实现
</PluginOutlet>
为这种“包装器”出口定义连接器将替换核心实现。对于包装器插件出口,同一社区中只能有一个活跃的主题或插件贡献连接器。
对于包装器插件出口,您可以使用 {{yield}} 关键字来渲染原始的核心实现。如果您仅希望在特定条件下替换核心实现,或者希望将其包裹在其他内容中,这会很有帮助。
定义连接器
选定出口后,为您的连接器确定一个名称。该名称在给定社区安装的所有主题/插件中必须是唯一的。例如:brand-official-topics。
在您的主题或插件中,定义一个新的 .gjs 连接器,路径格式如下:
![]()
{theme}/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs
![]()
{plugin}/assets/javascripts/discourse/connectors/{outlet-name}/{connector-name}.gjs
这些文件的内容将作为 Ember 组件进行渲染。有关 Ember 和 .gjs 格式的通用信息,请查阅 Ember 指南。
对于我们要假设的“品牌官方主题”连接器,文件内容可能如下所示:
<template>
<div class="alert alert-info">
此主题由
<a href="https://discourse.org/team">Discourse 团队</a>
的成员创建
</div>
</template>
使用出口参数
插件出口通过 @outletArgs 提供有关周围上下文的信息。传递给每个出口的参数各不相同。查看参数的简单方法是在模板中添加以下内容:
{{log @outletArgs}}
这将把参数记录到浏览器的开发者控制台中。它们将显示为 Proxy 对象——要查看参数列表,请展开代理的 [[Target]]。
在我们的 topic-above-posts 示例中,渲染的主题可在 @outletArgs.model 下找到。因此,我们可以这样添加团队成员的用户名:
<template>
<div class="alert alert-info">
此主题由
{{@outletArgs.model.details.created_by.username}}
(
<a href="https://discourse.org/team">Discourse 团队</a>
的成员)创建
</div>
</template>
添加更复杂的逻辑
有时,简单的模板不够用。若要在连接器中添加 JavaScript 逻辑,请将您的 .gjs 文件升级为导出基于类的组件。其功能与其他组件定义完全相同,并且可以包含服务注入。
在我们的 topic-above-posts 示例中,我们可能希望根据“在 UX 中优先显示用户名”的站点设置以不同方式渲染用户。.gjs 文件可能如下所示:
.../connectors/topic-above-posts/brand-official-topic.gjs:
import Component from "@glimmer/component";
import { service } from "@ember/service";
export default class BrandOfficialTopics extends Component {
@service siteSettings;
get displayName() {
const user = this.args.outletArgs.model.details.created_by;
if (this.siteSettings.prioritize_username_in_ux) {
return user.username;
} else {
return user.name;
}
}
<template>
<div class="alert alert-info">
此主题由
{{this.displayName}}
(
<a href="https://discourse.org/team">Discourse 团队</a>
的成员)创建
</div>
</template>
}
条件渲染
如果您仅希望在特定条件下渲染内容,通常只需将模板包裹在 Handlebars 的 {{#if}} 块中即可。如果这还不够,您可能需要使用 shouldRender 钩子来控制是否渲染连接器模板。
首先,确保您拥有如上所述的基于类的 .gjs 连接器。然后,添加一个 static shouldRender() 函数。扩展我们的示例:
import Component from "@glimmer/component";
export default class BrandOfficialTopics extends Component {
static shouldRender(outletArgs, helper) {
const firstPost = outletArgs.model.postStream.posts[0];
return firstPost.primary_group_name === "team";
}
// ... (其他逻辑)
<template>{{! ... }}</template>
}
现在,只有当主题的第一篇帖子由团队成员创建时,连接器才会被渲染。
shouldRender 在 Glimmer 自动追踪上下文中进行评估。任何引用属性(例如 outletArgs)的未来更改都会导致该函数重新评估。
引入新出口
如果您需要一个尚不存在的出口,请随时提交拉取请求,或在 Development 中开启一个话题。
本文档受版本控制——请在 GitHub 上提出修改建议。