在使用docsify构建Markdown文档时,如果想要支持数学公式,可以使用docsify-katex插件,但是该插件不支持化学公式mhchem扩展,比如下面的代码:

1\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扩展

1import 'katex/contrib/mhchem/mhchem';

由于mhchem扩展的语法格式中包含有美元符号,与行内公式使用的标记一样,所以需要先处理掉块内的美元符号: 再定义:

1const blockDollar = '!!blockDollar!!';
2const blockDollarRegx = /!!blockDollar!!/g;

再把处理公式块内的美元符号处理掉: 将hook.beforeEach函数如原代码:

1// Block
2.replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
3   return preMathBlockOpen + c + preMathBlockClose;
4})

改为:

1// Block
2.replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
3   let x = c.replace(/\$/g, blockDollar)
4   return preMathBlockOpen + x + preMathBlockClose;
5})

再修改hook.afterEach函数中原代码:

1mathRendered = mathRendered
2  .replace(
3    preMathBlockRegex,
4    function (m, code) {
5      let rendered = katex.renderToString(code, blockOptions);
6      return rendered;
7      }
8);

修改为:

1mathRendered = mathRendered
2  .replace(
3    preMathBlockRegex,
4    function (m, code) {
5      code = code.replace(blockDollarRegx, '$')
6      let rendered = katex.renderToString(code, blockOptions);
7      return rendered;
8      }
9);

即可。 修改好源码后,编译,使用新编译的js代码即可。

附上修改后的源码:

 1import 'katex/contrib/mhchem/mhchem';
 2import katex from 'katex';
 3
 4let options = {
 5  throwOnError: false,
 6  displayMode: false
 7};
 8let blockOptions = {
 9  throwOnError: false,
10  displayMode: true
11};
12
13const magicEscapedDollar = 'c194a9eb';
14const magicEscapedDollarRegex = /c194a9eb/g;
15const magicBacktickInCodeTag = 'c194a9ec';
16const magicBacktickInCodeTagRegex = /c194a9ec/g;
17const magicBacktickInDollars = 'c194a9ed';
18const magicBacktickInDollarsRegex = /c194a9ed/g;
19const magicEscapedBacktick = 'c194a9ee';
20const magicEscapedBacktickRegex = /c194a9ee/g;
21const magicDollarInBacktick = 'c194a9ef';
22const magicDollarInBacktickRegex = /c194a9ef/g;
23
24const preMathInlineOpen = 'c194a9eg<!-- begin-inline-katex';
25const preMathInlineClose = 'end-inline-katex-->';
26const preMathInlineRegex = /c194a9eg<!-- begin-inline-katex([\s\S]*?)end-inline-katex-->/g;
27
28
29const preMathBlockOpen = '<!-- begin-block-katex';
30const preMathBlockClose = 'end-block-katex-->';
31const preMathBlockRegex = /<!-- begin-block-katex([\s\S]*?)end-block-katex-->/g;
32
33const blockDollar = '!!blockDollar!!';
34const blockDollarRegx = /!!blockDollar!!/g;
35
36(function () {
37  function install(hook) {
38    hook.beforeEach(content => {
39      let mathPreserved = content
40        // Escape all <code>`</code>
41        .replace(/<code>(.*)<\/code>/g, function(a, b) {
42          return `<code>${b.replace(/`/g, magicBacktickInCodeTag)}</code>`;
43        })
44        // Escape all $`$
45        .replace(/\$`\$/g, magicBacktickInDollars)  
46        // Escape all \`{
47        .replace(/\\`\{/g, magicEscapedBacktick)
48        // Escape all \$
49        .replace(/\\\$/g, magicEscapedDollar)
50        // Escape all & in `...`
51        .replace(/(`{1,})([\s\S]*?)\1/g, function (a) {
52          return a.replace(/\$/g, magicDollarInBacktick);
53        })
54        // Recover all <code>`</code>
55        .replace(magicBacktickInCodeTagRegex, '`');
56      mathPreserved = mathPreserved
57        // Recover all $`$
58        .replace(magicBacktickInDollarsRegex, '$ `$')
59        // Recover all \`{
60        .replace(magicEscapedBacktickRegex, '\\`{');
61      mathPreserved = mathPreserved
62        // Block
63        .replace(/(\$\$)([\s\S]*?)(\$\$)/g, function (a, b, c) {
64          let x = c.replace(/\$/g, blockDollar)
65          return preMathBlockOpen + x + preMathBlockClose;
66        })
67        // Inline, no \$
68        .replace(/(\$)([\s\S]*?)(\$)/g, function (a, b, c) {
69          return preMathInlineOpen + c.replace(magicEscapedDollarRegex, '\\$') + preMathInlineClose;
70        })
71        .replace(magicEscapedDollarRegex, '\\$');
72      return mathPreserved;
73    });
74    hook.afterEach(function (html, next) {
75      let mathRendered = html
76        .replace(
77          preMathInlineRegex,
78          function (m, code) {
79            let rendered = katex.renderToString(code, options);
80            return rendered;
81          }
82        );
83      mathRendered = mathRendered
84        .replace(
85          preMathBlockRegex,
86          function (m, code) {
87            code = code.replace(blockDollarRegx, '$')
88            let rendered = katex.renderToString(code, blockOptions);
89            return rendered;
90          }
91        );
92      next(mathRendered
93        // Recover all & in `...`
94        .replace(magicDollarInBacktickRegex, '$'));
95    });
96  }
97
98  $docsify.plugins = [].concat(install, $docsify.plugins);
99}());