Discourse 包含数百个插件出口(Plugin Outlets),可用于向 Discourse UI 注入新内容或替换现有内容。“出口参数”(Outlet arguments)的提供使得可以根据上下文对内容进行自定义。
选择出口
要查找插件出口的名称,请在 Discourse 核心代码中搜索 “<PluginOutlet”,或者使用 plugin outlet locations 主题组件。(例如 topic-above-posts)。
包装器出口
核心代码中的一些出口看起来像 <PluginOutlet @name="foo" />。这些允许你注入新内容。其他出口则会像这样“包装”一个现有的核心实现:
<PluginOutlet @name="foo">
核心实现
</PluginOutlet>
为这种“包装器”出口定义连接器(connector)将会替换核心实现。只有一个活跃的主题/插件可以为一个包装器插件出口提供连接器。
对于包装器插件出口,你可以使用 {{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)的未来更改都会导致该函数重新求值。
引入新出口
如果你需要一个尚不存在的出口,请随意提交拉取请求(pull request),或在 Development 中开启一个话题。
本文档受版本控制 - 在 github 上建议更改。