Discourse 包含数百个插件出口(Plugin Outlets),可用于在 Discourse UI 中注入新内容或替换现有内容。系统会提供“出口参数”(Outlet arguments),以便根据上下文自定义内容。
选择出口
要查找插件出口的名称,请在 Discourse 核心代码中搜索 <PluginOutlet,或使用 插件出口位置 主题组件。(例如 topic-above-posts)。
包装器出口
核心中的一些出口看起来像 <PluginOutlet @name="foo" />。这些出口允许你注入新内容。其他出口则会像这样“包装”现有的核心实现:
<PluginOutlet @name="foo">
core implementation
</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 指南。
对于我们假设的“brand official topics”连接器,文件可能如下所示:
<template>
<div class="alert alert-info">
This topic was created by a member of the
<a href="https://discourse.org/team">Discourse Team</a>
</div>
</template>
使用出口参数
插件出口通过 @outletArgs 提供有关周围上下文的信息。传递给每个出口的参数各不相同。查看参数的一种简单方法是在模板中添加以下内容:
{{log @outletArgs}}
这会将参数记录到浏览器的开发者控制台中。它们将显示为 Proxy 对象——要查看参数列表,请展开代理的 [[Target]]。
在我们的 topic-above-posts 示例中,渲染的主题位于 @outletArgs.model 下。因此,我们可以像这样添加团队成员的用户名:
<template>
<div class="alert alert-info">
This topic was created by
{{@outletArgs.model.details.created_by.username}}
(a member of the
<a href="https://discourse.org/team">Discourse Team</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 topic was created by
{{this.displayName}}
(a member of the
<a href="https://discourse.org/team">Discourse Team</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";
}
// ... (any other logic)
<template>
{{! ... }}
</template>
}
现在,只有当主题的第一篇帖子由团队成员创建时,才会渲染该连接器。
shouldRender 在 Glimmer 自动跟踪上下文中求值。对任何引用属性(例如 outletArgs)的未来更改将导致重新评估该函数。
引入新出口
如果你需要一个尚不存在的出口,请随时发起拉取请求(Pull Request),或在 Development 频道中开启一个话题。
本文档受版本控制——建议更改 on github。