为当前使用主题 增加公式支持 以插件形式实现 不改主题
本次使用了插件方案,也列出了主题代码块方案,为了保证稳定性 我已经提前将远程文件备份在了本地插件目录 js和css文件夹
临时方案 直接js放置在主题文件 foot中
<!-- KaTeX 样式 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">
<!-- KaTeX 核心 JS -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>
<!-- 自动扫描渲染插件 -->
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"
onload="renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true}, // 块级公式
{left: '$', right: '$', display: false}, // 行内公式
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
throwOnError: false
});">
</script>
完美方案 插件化 不受升级影响
目录结构(和官方完全一致)
bl-plugins/
└── math-protect/
├── metadata.json
├── plugin.php
└── languages/
└── en.json
1. metadata.json(严格官方字段)
{
"author": "Custom",
"email": "",
"website": "",
"version": "1.0.0",
"releaseDate": "2026-08-30",
"license": "MIT",
"compatible": "3.0",
"notes": ""
}
2. languages/en.json
{
"plugin-data": {
"name": "Math Protect",
"description": "LaTeX formula protection with KaTeX rendering"
}
}
3. plugin.php(核心修复版,无自定义类继承)
<?php
if (!defined('BLUDIT')) {
die('Direct access forbidden.');
}
class pluginMathKaTeX extends Plugin
{
public function init(){}
public function siteHead()
{
return '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">' . PHP_EOL;
}
public function siteBodyEnd()
{
$out = '<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>' . PHP_EOL;
$out .= '<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"></script>' . PHP_EOL;
$out .= '<script>
document.addEventListener("DOMContentLoaded", function(){
if (!window.renderMathInElement) return;
const root = document.querySelector(".page-content") || document.querySelector(".content") || document.body;
renderMathInElement(root, {
delimiters: [
{left:"$$", right:"$$", display:true},
{left:"\\\\[", right:"\\\\]", display:true},
{left:"\\\\(", right:"\\\\)", display:false}
],
throwOnError: false,
strict: "ignore",
ignoredTags: ["script","noscript","style","textarea","pre","code","h1","h2","h3","h4","h5","h6","time"]
});
});
</script>'.PHP_EOL;
return $out;
}
}
- 保留原生写作语法:块级
$$,行内\( \);禁止使用单 $ 行内公式; - 固有缺陷:auto‑render 会扫描页面全部文本节点;正文出现数学类 Unicode 字符(U+2212 长减号等)会发生普通文字字体拉长,库本身限制,代码层面无法彻底根除,只能靠写作规范规避;
- 配置显式禁用
$分隔符,消除单 $ 误渲染。
(
真正的破坏者是 Parsedown(Bludit 内置 Markdown 解析器)。
Parsedown 遇到紧贴同一行的$$...$$,不会把它保留成原始文本输出到 HTML。
- 如果
$$没有单独成行,Parsedown 会把$$当成普通字符,或被解析成文本标记、甚至被转义; - auto‑render 要工作,前提条件:输出后的 HTML 源码里必须完整保留
$$内容$$这串文本。
一旦 Parsedown 解析阶段吃掉 / 转义了
$$,前端 JS 拿不到标记,自然不渲染。
)
做不到稳定支持单行紧凑写法 $$公式$$。
原因不在 JS,在 PHP 侧 Parsedown 解析已经破坏标记,插件没有安全钩子去预处理原始 Markdown(前面已经验证:钩子要么 500,要么修改被覆盖)。
可以理解为:Parsedown 会 “吃掉” 同行紧贴的 $$ 标记,JS 再强大也拿不到标记文本。
当前环境下的现实边界
- 块公式:想要稳定渲染, 必须把(分别单独占一行;单行紧凑
\)xxx$$不可靠,时而有效时而失效,取决于段落、换行、周围 markdown 符号。 - 行内公式:
\( ... \)可以用,但要留意反斜杠不要被 Parsedown 转义;编辑器保存后看网页源码,确认 HTML 里面确实是\(不是\\(。 - 没有办法在不修改 Bludit 内核 / 主题的前提下,修复 Parsedown 对
$$单行写法的破坏。
新建测试文章 2026−8−28:
1.2026−8−28
2.经过对照官方插件结构逐层审计,致命错误的核心触发点是 ParsedownMath extends Parsedown 类继承
3.$$\text{GL} = \frac{\text{GI} \times \text{实际摄入纯碳水化合物克数(g)}}{100}$$
4.行内公式测试:血糖生成指数
$$GI = \frac{\text{餐后血糖曲线下面积}}{\text{标准食物血糖曲线下面积}} \times 100$$
1.2026−8−28
2.经过对照官方插件结构逐层审计,**致命错误的核心触发点是 `ParsedownMath extends Parsedown` 类继承**
3.$$\text{GL} = \frac{\text{GI} \times \text{实际摄入纯碳水化合物克数(g)}}{100}$$
4.行内公式测试:血糖生成指数
$$GI = \frac{\text{餐后血糖曲线下面积}}{\text{标准食物血糖曲线下面积}} \times 100$$
- 前台查看是否正常渲染。
公式测试组
1 块公式基准(预期可渲染)
$$E = mc^2$$
2 行内尝试1:标准 ( )
$$文本 ( a^2+b^2=c^2 ) 测试结束。$$
3 行内尝试2:双反斜杠 \( \)
文本 $$\( a^2+b^2=c^2 \) $$测试结束。
4 行内尝试3:单$(插件未启用$分隔符,预期原样文本)
文本 $$ a^2+b^2=c^2 $$ 测试结束。
5 行内尝试4:双$$挤在行内(块语法强行放段落,不稳定)
测试 $$E=mc^2$$ 文本后面。
6 简单分式块
$$\text{GL} = \frac{\text{GI}\times\text{碳水}}{100}$$
7 简单行内分式 ( \frac{a}{b} )
$$测试 ( \frac{a}{b} ) 文本。$$
8 行内双反斜杠分式 \( \frac{a}{b} \)
测试 \( \frac{a}{b} \) 文本。
$$ ... $$,可以渲染出公式 可临时巧用
测试发现:把包含
\(的整段全部外层套$$ ... $$,可以渲染出公式,但普通文本被置于 LaTeX 数学模式,文字字体、空格、中文渲染行为异常,属于测试技巧,不可用于正式内容,不是真正行内公式解决方案。
Bludit 3.22.0 + Parsedown + auto‑render,不改插件条件下:
- 生产可用:独立换行块公式
$$ … $$- 伪行内(仅测试):外层
$$包裹整段,普通文字排版受损- 标准
\( \)行内:原生环境无法直接工作;想要真正行内公式,只能选择改插件(双反斜杠语法)或者短代码插件方案。
优化了复杂数学公式渲染
只需要修改 插件主文件
<?php
if (!defined('BLUDIT')) {
die('Direct access forbidden.');
}
class pluginMathKaTeX extends Plugin
{
public function init() {}
public function siteHead()
{
return '<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css">' . PHP_EOL;
}
public function siteBodyEnd()
{
$out = '<script src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js"></script>' . PHP_EOL;
$out .= '<script src="https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js"></script>' . PHP_EOL;
$out .= '<script>
(function() {
if (!window.renderMathInElement) return;
// 优先匹配 Blowfish 主题正文容器
const root = document.querySelector(".content") || document.querySelector(".page-content") || document.body;
renderMathInElement(root, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "\\(", right: "\\)", display: false}
],
throwOnError: false,
strict: "ignore",
ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code", "time"]
});
})();
</script>' . PHP_EOL;
return $out;
}
}
用 <div> 包裹整个公式块,Parsedown 会把它当作原生 HTML 块,内部内容不做 Markdown 解析:
如果想要更好的性能,可以把渲染触发改成 requestIdleCallback,避免阻塞首屏;或者开启 macros 自定义命令
测试代码
<div>
$$
SCN \rightarrow SPZ \rightarrow DMH \rightarrow
\begin{cases}
\text{VLPO/视前区}\\
\text{Orexin}\\
\text{LC等觉醒系统}
\end{cases}
$$
</div>
本地化当前插件
先在插件目录下载远程js,避免远程js资源失效或被污染打不开
配套下载脚本 download_katex.php(放到 /bl-plugins/Latex/) 打开,下载后删掉
<?php
// download_katex.php 放在 /bl-plugins/Latex/
$saveDir = __DIR__ . '/js';
if (!file_exists($saveDir)) {
mkdir($saveDir, 0755, true);
}
$files = [
'katex.min.css' => 'https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.css',
'katex.min.js' => 'https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/katex.min.js',
'auto-render.min.js' => 'https://cdn.jsdelivr.net/npm/katex@0.16.11/dist/contrib/auto-render.min.js',
];
foreach ($files as $filename => $url) {
$savePath = $saveDir . '/' . $filename;
echo "正在下载:{$url}<br>";
$data = file_get_contents($url);
if ($data !== false) {
file_put_contents($savePath, $data);
echo "✅ 保存成功 -> js/{$filename}<br><br>";
} else {
echo "❌ 下载失败:{$url}<br><br>";
}
}
echo "<hr>全部任务完成!请删除 download_katex.php";
再修复插件主文件链接
<?php
if (!defined('BLUDIT')) {
die('Direct access forbidden.');
}
class pluginMathKaTeX extends Plugin
{
public function init() {}
public function siteHead()
{
// 根绝对路径,适配全站
return '<link rel="stylesheet" href="/bl-plugins/Latex/js/katex.min.css">' . PHP_EOL;
}
public function siteBodyEnd()
{
$out = '<script src="/bl-plugins/Latex/js/katex.min.js"></script>' . PHP_EOL;
$out .= '<script src="/bl-plugins/Latex/js/auto-render.min.js"></script>' . PHP_EOL;
$out .= '<script>
(function() {
if (!window.renderMathInElement) return;
// 优先匹配 Blowfish 主题正文容器
const root = document.querySelector(".content") || document.querySelector(".page-content") || document.body;
renderMathInElement(root, {
delimiters: [
{left: "$$", right: "$$", display: true},
{left: "\\[", right: "\\]", display: true},
{left: "\\(", right: "\\)", display: false}
],
throwOnError: false,
strict: "ignore",
ignoredTags: ["script", "noscript", "style", "textarea", "pre", "code", "time"]
});
})();
</script>' . PHP_EOL;
return $out;
}
}