一、概述
MathJax是一款开源的JavaScript显示引擎,适用所有现代浏览器,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。
目前,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言。
MathJax官网:MathJax官网
Github地址:MathJax Github
中文文档地址:MathJax中文文档
英文文档地址:MathJax英文文档
MathJax语法:MathJax语法
二、安装
1、引入
MathJax使用网络字体(大部分浏览器都支持)去产生高质量的排版,使其在所有分辨率都可缩放和显示。
字体资源较大,所以,通常推荐使用CDN网络分发进行加载。
国外用户基本上使用Jsdelivr。
<script id="MathJax-script" <strong>async</strong> src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
国内用户使用以下cdn
3.x版本
<script type="text/javascript" id="MathJax-script" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/3.0.0/es5/tex-mml-chtml.js">
</script>
2.x版本
<script type="text/javascript" async
src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
需要注意的是,MathJax 3.x和2.x版本差异比较大,3.x版本采用模块化开发,可以按需加载。部分2.x版本API在3.x中过时不可用。出于简便性和稳定性考虑,我选择了2.x版本。
2、配置
mathjax.js
let isMathjaxConfig = false;//用于标识是否配置
const initMathjaxConfig = () => {
if (!window.MathJax) {
return;
}
window.MathJax.Hub.Config({
showProcessingMessages: true, //关闭js加载过程信息
messageStyle: "none", //none不显示信息 normal和simple显示
jax: ["input/TeX", "output/HTML-CSS"],
tex2jax: {
inlineMath: [["$", "$"], ["\\(", "\\)"]], //行内公式选择符
displayMath: [["$$", "$$"], ["\\[", "\\]"]], //段内公式选择符
// skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"], //跳过指定标签
//includeHtmlTags: { //配置在数学公式里可以出现哪些标签,例如公式里出现 n可用于换行
// br: '\n', wbr: '', '#comment': ''
//}
},
"HTML-CSS": {
availableFonts: ["STIX", "TeX"],
showMathMenu: false //右击菜单显示
}
});
isMathjaxConfig = true; //配置完成,改为true
};
const MathQueue = function (elementId) {
if (!window.MathJax) {
return;
}
window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, document.getElementById(elementId)]);
};
export default {
isMathjaxConfig,
initMathjaxConfig,
MathQueue
}
更多配置详见概述中的文档链接。
其中,需要注意的是,以上配置基于2.7.5版本,而window.MathJax.Hub.Queue(["Typeset", MathJax.Hub])
该方法在3.x版本中已过时。
在以下示例2中,使用的是MathJax.tex2chtmlPromise()
函数,但也存在渲染的dom中存在非公式组件会样式丢失的问题。
查阅官方文档,看到如下:
因此,在3.x版本中,可以使用MathJax.typesetPromise()
替代实现window.MathJax.Hub.Queue(["Typeset", MathJax.Hub])
index.js
import mathjax from '@/math/mathjax.js'
Vue.prototype.$mathjax = mathjax;
三、例子
1、静态页面渲染公式
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">
<title>MathJax v3 with TeX input and HTML output</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script>
MathJax = {
tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]}
};
</script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
</head>
<body>
<h1>MathJax v3 beta: TeX input, HTML output test</h1>
<p>
When $a \ne 0$, there are two solutions to \(ax^2 + bx + c = 0\) and they are
$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
</p>
<h2>The Lorenz Equations</h2>
<p>
\begin{align}
\dot{x} & = \sigma(y-x) \\
\dot{y} & = \rho x - y - xz \\
\dot{z} & = -\beta z + xy
\end{align}
</p>
<h2>The Cauchy-Schwarz Inequality</h2>
<p>\[
\left( \sum_{k=1}^n a_k b_k \right)^{\!\!2} \leq
\left( \sum_{k=1}^n a_k^2 \right) \left( \sum_{k=1}^n b_k^2 \right)
\]</p>
<h2>A Cross Product Formula</h2>
<p>\[
\mathbf{V}_1 \times \mathbf{V}_2 =
\begin{vmatrix}
\mathbf{i} & \mathbf{j} & \mathbf{k} \\
\frac{\partial X}{\partial u} & \frac{\partial Y}{\partial u} & 0 \\
\frac{\partial X}{\partial v} & \frac{\partial Y}{\partial v} & 0 \\
\end{vmatrix}
\]</p>
<h2>The probability of getting \(k\) heads when flipping \(n\) coins is:</h2>
<p>\[P(E) = {n \choose k} p^k (1-p)^{ n-k} \]</p>
<h2>An Identity of Ramanujan</h2>
<p>\[
\frac{1}{(\sqrt{\phi \sqrt{5}}-\phi) e^{\frac25 \pi}} =
1+\frac{e^{-2\pi}} {1+\frac{e^{-4\pi}} {1+\frac{e^{-6\pi}}
{1+\frac{e^{-8\pi}} {1+\ldots} } } }
\]</p>
<h2>A Rogers-Ramanujan Identity</h2>
<p>\[
1 + \frac{q^2}{(1-q)}+\frac{q^6}{(1-q)(1-q^2)}+\cdots =
\prod_{j=0}^{\infty}\frac{1}{(1-q^{5j+2})(1-q^{5j+3})},
\quad\quad \text{for $|q| < 1$}.
\]</p>
<h2>Maxwell's Equations</h2>
<p>
\begin{align}
\nabla \times \vec{\mathbf{B}} -\, \frac1c\, \frac{\partial\vec{\mathbf{E}}}{\partial t} & = \frac{4\pi}{c}\vec{\mathbf{j}} \\
\nabla \cdot \vec{\mathbf{E}} & = 4 \pi \rho \\
\nabla \times \vec{\mathbf{E}}\, +\, \frac1c\, \frac{\partial\vec{\mathbf{B}}}{\partial t} & = \vec{\mathbf{0}} \\
\nabla \cdot \vec{\mathbf{B}} & = 0
\end{align}
</p>
<h2>In-line Mathematics</h2>
<p>Finally, while display equations look good for a page of samples, the
ability to mix math and text in a paragraph is also important. This
expression $\sqrt{3x-1}+(1+x)^2$ is an example of an inline equation. As
you see, MathJax equations can be used this way as well, without unduly
disturbing the spacing between lines.</p>
</body>
</html>
2、事件触发渲染
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="x-ua-compatible" content="ie=edge">
<meta name="viewport" content="width=device-width">
<title>MathJax v3 with interactive TeX input and HTML output</title>
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml.js"></script>
<script>
function convert() {
//
// Get the TeX input
//
var input = document.getElementById("input").value.trim();
//
// Disable the display and render buttons until MathJax is done
//
var display = document.getElementById("display");
var button = document.getElementById("render");
button.disabled = display.disabled = true;
//
// Clear the old output
//
output = document.getElementById('output');
output.innerHTML = '';
//
// Reset the tex labels (and automatic equation numbers, though there aren't any here).
// Get the conversion options (metrics and display settings)
// Convert the input to CommonHTML output and use a promise to wait for it to be ready
// (in case an extension needs to be loaded dynamically).
//
MathJax.texReset();
var options = MathJax.getMetricsFor(output);
options.display = display.checked;
MathJax.tex2chtmlPromise(input, options).then(function (node) {
//
// The promise returns the typeset node, which we add to the output
// Then update the document to include the adjusted CSS for the
// content of the new equation.
//
output.appendChild(node);
MathJax.startup.document.clear();
MathJax.startup.document.updateDocument();
}).catch(function (err) {
//
// If there was an error, put the message into the output instead
//
output.appendChild(document.createElement('pre')).appendChild(document.createTextNode(err.message));
}).then(function () {
//
// Error or not, re-enable the display and render buttons
//
button.disabled = display.disabled = false;
});
}
</script>
<style>
#frame {
max-width: 40em;
margin: auto;
}
#input {
border: 1px solid grey;
margin: 0 0 .25em;
width: 100%;
font-size: 120%;
box-sizing: border-box;
}
#output {
font-size: 120%;
margin-top: .75em;
border: 1px solid grey;
padding: .25em;
min-height: 2em;
}
#output > pre {
margin-left: 5px;
}
.left {
float: left;
}
.right {
float: right;
}
</style>
</head>
<body>
<div id="frame">
<h1>MathJax v3: TeX to HTML</h1>
<textarea id="input" rows="15" cols="10">
%
% Enter TeX commands below
%
x = {-b \pm \sqrt{b^2-4ac} \over 2a}.
</textarea>
<br />
<div class="left">
<input type="checkbox" id="display" checked onchange="convert()"> <label for="display">Display style</label>
</div>
<div class="right">
<input type="button" value="Render TeX" id="render" onclick="convert()" />
</div>
<br clear="all" />
<div id="output"></div>
</div>
</body>
</html>
3、动态数据解析
// v-html 加载动态数据
<div v-html="contnt">
// 之后调用MathJax重新渲染
this.$nextTick(() => {
if (this.$mathjax.isMathjaxConfig) {
this.$mathjax.initMathjaxConfig();
}
this.$mathjax.MathQueue("app");
});
3、更多例子,见 MathJax
参考: