最近在复习万恶的数值分析,原本手抄的公式笔记阅读起来不太方便,打算用 MathJax 重写公式再整理到 Hexo 博客上。奇怪的是,公式在本地 Typora 上渲染的完全 OK,搬 Hexo 上咋就出问题了?(重启喝水都试过了)
例如e_r(x^{*})=\frac{x-x^*}{x^*}
,讲道理它应该长成下面的样子:
然而实际上它是这个样子:$e_r(x^{})=\frac{x-x^}{x^*}$
又或者f_n=f_{n-1}+f_{n-2}
,讲道理它应该生的和下边一样俊俏:
然而也不幸长残了:$f_n=f_{n-1}+f_{n-2}$
What are you 弄啥嘞?😡
注:针对两个单独的
_
的语义冲突已在后文中修复,因此上面的行内公式显示正常。未修复之前,Markdown 渲染器仍然会将两个单独的_
之间的内容渲染为<em>
标签,显示效果为:$fn=f{n-1}+f_{n-2}$
问题分析
不难发现,上边既然有成功的渲染,就说明 MathJax 本身没有罢工。而且,仔细观察还会发现,第一个公式中最开始两个*
中间的字体变成了斜体;第二个公式中最开始两个_
也是同样的情况。审查元素发现,第一个公式中的斜体部分被渲染成了<em>
标签:
<em>})=\frac{x-x^</em>
这样来看答案就很清楚了:这个错误是由 Markdown 渲染器(默认的是 hexo-renderer-marked )引起的。Markdown 本身并不支持 Latex,在渲染时正则匹配到两个_
或*
就会把下划线替换成了<em>
,于是到了 MathJax 渲染公式时就彻底懵了。
解决办法也很简单:使用 hexo-renderer-kramed 替换 Hexo 默认的渲染器 hexo-renderer-marked。
替换默认渲染引擎
hexo-renderer-kramed 是 hexo-renderer-marked 的 Fork 修改版,仅针对 MathJax 渲染的语义冲突问题进行了修改,因此可以放心使用。在 Hexo 根目录下执行以下命令替换默认渲染引擎:
npm uninstall hexo-renderer-marked --save
npm install hexo-renderer-kramed --save
更换渲染引擎后,整行公式就可以正常显示了,然而行内公式还是会遇到<em>
标签语义冲突的问题。在 Markdown 语法中,用$$
包括起来的内容表示整行公式,用$
包括起来的内容表示行内公式。之所以行内公式的渲染依然存在问题,是因为 hexo-renderer-kramed 引擎同样存在语义冲突的问题。
解决语义冲突
在博客根目录下,找到node_modules/kramed/lib/rules/inline.js
文件,在inline
变量中做出如下修改:
var inline = {
// escape: /^\\([\\`*{}\[\]()#$+\-.!_>])/, 第 11 行, 将其修改为
escape: /^\\([`*\[\]()#$+\-.!_>])/,
autolink: /^<([^ >]+(@|:\/)[^ >]+)>/,
url: noop,
html: /^<!--[\s\S]*?-->|^<(\w+(?!:\/|[^\w\s@]*@)\b)*?(?:"[^"]*"|'[^']*'|[^'">])*?>([\s\S]*?)?<\/\1>|^<(\w+(?!:\/|[^\w\s@]*@)\b)(?:"[^"]*"|'[^']*'|[^'">])*?>/,
link: /^!?\[(inside)\]\(href\)/,
reflink: /^!?\[(inside)\]\s*\[([^\]]*)\]/,
nolink: /^!?\[((?:\[[^\]]*\]|[^\[\]])*)\]/,
reffn: /^!?\[\^(inside)\]/,
strong: /^__([\s\S]+?)__(?!_)|^\*\*([\s\S]+?)\*\*(?!\*)/,
// em: /^\b_((?:__|[\s\S])+?)_\b|^\*((?:\*\*|[\s\S])+?)\*(?!\*)/, 第 20 行,将其修改为
em: /^\*((?:\*\*|[\s\S])+?)\*(?!\*)/,
code: /^(`+)\s*([\s\S]*?[^`])\s*\1(?!`)/,
br: /^ {2,}\n(?!\s*$)/,
del: noop,
text: /^[\s\S]+?(?=[\\<!\[_*`$]| {2,}\n|$)/,
math: /^\$\$\s*([\s\S]*?[^\$])\s*\$\$(?!\$)/,
};
第 11 行的修改去掉了\\
和{}
,目的是在原基础上去掉对\
、{
、}
的转义 (escape)。
第 20 行的修改去掉了\b_((?:__|[\s\S])+?)_\b
,目的是去掉对两个_
之间内容的<em>
标签转义。
也就是说,依然可以在 Hexo 中使用*
表示斜体,但用_
表示_斜体_就不会生效了。
另外在行内公式中,针对两个*
的语义冲突依旧存在,目前来看没什么比较好的解决办法(摊手)。
按需加载 MathJax
hexo-theme-indigo 默认集成了 MathJax,然而只在主题配置文件中定义了 MathJax 的开关。这样就会造成一个问题:
只要
theme.mathjax
为true
,所有文章页面都会引入 MathJax.js,在不需要使用 MathJax 的页面中会带来毫无必要的时间和资源开销。
因此需要修改主题模板文件,使其按需加载 MathJax.js。
还是以 hexo-theme-indigo 为例,首先在主题配置文件theme/_config.yaml
中,将MathJax
设置为true
:
mathjax: true
随后修改主题模板文件中的判定条件。以 hexo-theme-indigo 为例,其判定是否引入MathJax.js
的代码在layout/_partial/plugins/mathjax.ejs
文件中:
<% if (theme.mathjax){ %>
<!-- mathjax config similar to math.stackexchange -->
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [ ['$','$'], ["\\(","\\)"] ],
processEscapes: true,
skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
}
});
MathJax.Hub.Queue(function() {
var all = MathJax.Hub.getAllJax(), i;
for(i=0; i < all.length; i += 1) {
all[i].SourceElement().parentNode.className += ' has-jax';
}
});
</script>
<script async src="//cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML" async></script>
<% } %>
显然,只需修改第一行的判定条件为双重判定:
<% if ( theme.mathjax && page.mathjax ){ %>
最后在需要使用 MathJax 文章的 Front-matter 中,将Mathjax
设置为true
,即可在该页面中引入 MathJax.js 而不影响其他页面:
---
title: 测试Mathjax
category:
- 前端
tags:
- Hexo
- MathJax
date: 2018-10-29 19:58:35
mathjax: true
---
这里还有一个小问题:博客的首页也可能会调用 MathJax.js 渲染公式,而按照以上设置,非文章页面是不会引入 MathJax.js 的。这里给出两种解决办法:
- 合理设置
<!-- more -->
标签位置,确保首页不会展示公式。 - 修改
mathjax.ejs
的判定条件如下,首页同样引入 MathJax.js:
<% if ( theme.mathjax && ( page.mathjax || is_home() ) ){ %>
问题解决~最后来测试一下😎
参考文章
- 常用数学符号的 LaTex 表示方法
- 一份不太简短的 LaTex 2 介绍.pdf
- Online LaTex Equation Editor | CODECOGS
- 在 Hexo 中渲染 MathJax 数学公式 | 码迷
- Hexo 博客 MathJax 公式渲染问题 | 博客园
- Hexo 博客 MathJax 公式渲染问题 | 衡仔的技术小窝
- 如何处理 Hexo 和 MathJax 的兼容问题 | 林肯先生的 Blog
- 在 Hexo 中渲染 MathJax 数学公式 | 简书
- 在 Hexo 博客中使用 MathJax 写 LaTex 数学公式 | CSDN
- Hexo 中插入数学公式 | Steven’s Space
- 前端整合 MathjaxJS 配置笔记 | 博客园
- hexo-renderer-kramed | Github
- hexo-renderer-marked | Github
- MathJax.org
- The LaTex project