Discourse 是一个单页应用程序。您遇到的问题是因为您使用的脚本未意识到这一点。当您访问 Discourse 的主页或其他任何页面时,会得到类似以下的内容:
<html>
<head>
head 内容,包括您的脚本
</head>
<body>
<section id="main">
页面内容
</section>
</body>
</html>
当您导航到另一个页面时,唯一重新加载的内容是以下部分内部的内容:
<section id="main">
因此,DOM 已更改,您的自定义脚本不会再次触发。如果您尝试直接访问主题页面,您会发现它可以正常加载。
。
那么,现在的问题是如何使其与 Discourse 协同工作。
plugin-api 提供了一个方法,可用于“装饰”帖子。
https://github.com/discourse/discourse/blob/main/app/assets/javascripts/discourse/app/lib/plugin-api.js#L282-L318
您可以使用它在帖子渲染时触发第三方脚本。
以下是您需要的代码。将其添加到您主题的 common > header 选项卡中。
<script type="text/discourse-plugin" version="0.8">
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
const loadScript = require("discourse/lib/load-script").default;
const { iconHTML } = require("discourse-common/lib/icon-library");
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
class: "woxo-preview-icon"
});
const previewMarkup = () => {
const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
return markup;
};
// 创建帖子装饰器
api.decorateCookedElement(
post => {
const woxoWidgets = post.querySelectorAll("div[data-mc-src]");
if (woxoWidgets.length) {
woxoWidgets.forEach(woxoWidget => {
if (post.classList.contains("d-editor-preview")) {
woxoWidget.innerHTML = previewMarkup();
return;
}
loadScript(WOXO_SCRIPT_SRC).then(() => {
const script = document.head.querySelector(
`script[src*="cdn2.woxo.tech"]`
);
script.dataset.usrc = "";
window.MC.Loader.init();
});
});
}
},
{ id: "render-woxo-widgets" }
);
</script>
接下来,您需要为 CSP 添加几个域名。将这些添加到您的
content_security_policy_script_src
站点设置中:
https://*.woxo.tech/
https://us-central1-core-period-259421.cloudfunctions.net/availableComponentTracks
最后,您需要为静态编辑器预览添加一些 CSS。
这应放在您主题的 common > CSS 选项卡中。
.woxo-preview {
height: 400px;
width: 100%;
background: var(--primary-low);
display: flex;
align-items: center;
justify-content: center;
.woxo-preview-icon {
font-size: var(--font-up-4);
color: var(--primary-high);
}
}
然后,您只需在任意帖子中添加以下内容:
<div data-mc-src="f4b43a8f-c188-4f80-8206-36d9f7529f13#instagram"></div>
小部件将渲染并完全正常运行。
如果您查看 JavaScript 代码,会注意到其顶部有两个选项。
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
将 WOXO_SCRIPT_SRC 更改为 woxo 提供的 src 地址。对于您创建的所有嵌入内容,该地址应相同。
将 PREVIEW_ICON 更改为您希望在编辑器预览中使用的图标名称。在编辑器中运行此代码开销较大,因此编辑器会显示一个静态预览,如下所示:
您选择的图标将显示在中间。
如果您想跟随了解代码的具体执行过程,以下是带注释的代码副本:
带注释的代码
<script type="text/discourse-plugin" version="0.8">
// 选项
const WOXO_SCRIPT_SRC = "https://cdn2.woxo.tech/a.js#616348fb53c1e8001686c619";
const PREVIEW_ICON = "heart";
// 我们使用 Discourse 的 Load script 库来确保脚本正确加载。
// 不用担心,它足够智能,如果脚本已加载则不会重复加载。
const loadScript = require("discourse/lib/load-script").default;
// 我们加载 Discourse 的 iconHTML 函数以获取我们要在静态编辑器预览中使用的图标 SVG。
const { iconHTML } = require("discourse-common/lib/icon-library");
// 设置编辑器预览图标
const composerPreviewIcon = iconHTML(PREVIEW_ICON, {
class: "woxo-preview-icon"
});
// 创建编辑器预览标记的辅助函数
const previewMarkup = () => {
const markup = `<div class="woxo-preview">${composerPreviewIcon}</div>`;
return markup;
};
// 创建帖子装饰器
api.decorateCookedElement(
post => {
// 此帖子是否包含 woxo 小部件?
const woxoWidgets = post.querySelectorAll("div[data-mc-src]");
// 是的,那么让我们做一些处理。
if (woxoWidgets.length) {
// 遍历每个 woxo 小部件
woxoWidgets.forEach(woxoWidget => {
// 如果是编辑器中的小部件,将其替换为静态预览并提前退出
if (post.classList.contains("d-editor-preview")) {
woxoWidget.innerHTML = previewMarkup();
return;
}
// 如果不在编辑器中,则加载 woxo 脚本。
loadScript(WOXO_SCRIPT_SRC).then(() => {
// woxo 脚本非常特殊。如果脚本标签没有空的 data-usrc 属性,它将无法工作。因此,让我们添加它。
const script = document.head.querySelector(
`script[src*="cdn2.woxo.tech"]`
);
script.dataset.usrc = "";
// 一切就绪,让我们调用 woxo 脚本中的 init 方法。
window.MC.Loader.init();
});
});
}
},
// 为装饰器添加 id 以避免内存泄漏
{ id: "render-woxo-widgets" }
);
</script>