在使用docsify构建Markdown文档时,如果想要支持数学公式,可以使用docsify-katex插件,但是该插件不支持化学公式mhchem扩展,比如下面的代码:
\ce{Zn^2+ <=>[+ 2OH-][+ 2H+] $\underset{\text{amphoteres Hydroxid}}{\ce{Zn(OH)2 v}}$ <=>[+ 2OH-][+ 2H+] $\underset{\text{Hydroxozikat}}{\ce{[Zn(OH)4]^2-}}$}
正常显示应该为:
docsify-katex已经很久没更新了,最新的katex已经支持mhchem扩展。为了让docsify-katex也支持mhchem扩展,需要做如下修改:
首先引入mhchem扩展
import 'katex/contrib/mhchem/mhchem';
由于mhchem扩展的语法格式中包含有美元符号,与行内公式使用的标记一样,所以需要先处理掉块内的美元符号:
再定义:
const blockDollar = '!!blockDollar!!';
const blockDollarRegx = /!!blockDollar!!/g;
再把处理公式块内的美元符号处理掉:
将hook.beforeEach函数如原代码:
// Block
.replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
return preMathBlockOpen + c + preMathBlockClose;
})
改为:
// Block
.replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
let x = c.replace(/\$/g, blockDollar)
return preMathBlockOpen + x + preMathBlockClose;
})
再修改hook.afterEach函数中原代码:
mathRendered = mathRendered
.replace(
preMathBlockRegex,
function (m, code) {
let rendered = katex.renderToString(code, blockOptions);
return rendered;
}
);
修改为:
mathRendered = mathRendered
.replace(
preMathBlockRegex,
function (m, code) {
code = code.replace(blockDollarRegx, '$')
let rendered = katex.renderToString(code, blockOptions);
return rendered;
}
);
即可。
修改好源码后,编译,使用新编译的js代码即可。
附上修改后的源码:
import 'katex/contrib/mhchem/mhchem';
import katex from 'katex';
let options = {
throwOnError: false,
displayMode: false
};
let blockOptions = {
throwOnError: false,
displayMode: true
};
const magicEscapedDollar = 'c194a9eb';
const magicEscapedDollarRegex = /c194a9eb/g;
const magicBacktickInCodeTag = 'c194a9ec';
const magicBacktickInCodeTagRegex = /c194a9ec/g;
const magicBacktickInDollars = 'c194a9ed';
const magicBacktickInDollarsRegex = /c194a9ed/g;
const magicEscapedBacktick = 'c194a9ee';
const magicEscapedBacktickRegex = /c194a9ee/g;
const magicDollarInBacktick = 'c194a9ef';
const magicDollarInBacktickRegex = /c194a9ef/g;
const preMathInlineOpen = 'c194a9eg<!-- begin-inline-katex';
const preMathInlineClose = 'end-inline-katex-->';
const preMathInlineRegex = /c194a9eg<!-- begin-inline-katex([\s\S]*?)end-inline-katex-->/g;
const preMathBlockOpen = '<!-- begin-block-katex';
const preMathBlockClose = 'end-block-katex-->';
const preMathBlockRegex = /<!-- begin-block-katex([\s\S]*?)end-block-katex-->/g;
const blockDollar = '!!blockDollar!!';
const blockDollarRegx = /!!blockDollar!!/g;
(function () {
function install(hook) {
hook.beforeEach(content => {
let mathPreserved = content
// Escape all <code>`</code>
.replace(/<code>(.*)<\/code>/g, function(a, b) {
return `<code>${b.replace(/`/g, magicBacktickInCodeTag)}</code>`;
})
// Escape all $`$
.replace(/\$`\$/g, magicBacktickInDollars)
// Escape all \`{
.replace(/\\`\{/g, magicEscapedBacktick)
// Escape all \$
.replace(/\\\$/g, magicEscapedDollar)
// Escape all & in `...`
.replace(/(`{1,})([\s\S]*?)\1/g, function (a) {
return a.replace(/\$/g, magicDollarInBacktick);
})
// Recover all <code>`</code>
.replace(magicBacktickInCodeTagRegex, '`');
mathPreserved = mathPreserved
// Recover all $`$
.replace(magicBacktickInDollarsRegex, '$ `$')
// Recover all \`{
.replace(magicEscapedBacktickRegex, '\\`{');
mathPreserved = mathPreserved
// Block
.replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
let x = c.replace(/\$/g, blockDollar)
return preMathBlockOpen + x + preMathBlockClose;
})
// Inline, no \$
.replace(/(\$)([\s\S]*?)(\$)/g, function (a, b, c) {
return preMathInlineOpen + c.replace(magicEscapedDollarRegex, '\\$') + preMathInlineClose;
})
.replace(magicEscapedDollarRegex, '\\$');
return mathPreserved;
});
hook.afterEach(function (html, next) {
let mathRendered = html
.replace(
preMathInlineRegex,
function (m, code) {
let rendered = katex.renderToString(code, options);
return rendered;
}
);
mathRendered = mathRendered
.replace(
preMathBlockRegex,
function (m, code) {
code = code.replace(blockDollarRegx, '$')
let rendered = katex.renderToString(code, blockOptions);
return rendered;
}
);
next(mathRendered
// Recover all & in `...`
.replace(magicDollarInBacktickRegex, '$'));
});
}
$docsify.plugins = [].concat(install, $docsify.plugins);
}());