从入职新公司以来,就接手了一个关于作业的需求,于是数学公式的显示问题甩也甩不掉,甚至还会有其他需求因为需要展示公式而分给我,也是因为这样才决定好好整理一下关于前端公式显示的思路。
一、LaTex是什么
实话讲,最开始我以为LaTex就是专门用来标记数学公式的一门语言,直到有一天我看到这篇文章(http://www.ctex.org/documents/shredder/tex_frame.html),才知道自己的想法对于LaTex来说多么表面
总结一下:LaTex的基础是Tex,Tex是一个排版系统,是一个拥有自己完整体系的语法,可以用于各种科研、试卷甚至音乐需要,而LaTex建立在Tex的基础上进行性能扩展,相当于Tex的一个宏包
而对于使用者来说,由于LaTex的使用还是有一定的难度和复杂度,大家还是只在公式方面比较青睐它,所以大多数我们常看见的应用也都是与公式相关
二、公式输入时的即时显示MathQuill
MathQuill是一个JS库,通过自己暴露出来的接口调用来即时显示输入的公式结果,一般用来和键盘输入的input配合使用,官网链接(http://mathquill.com/)
一般使用的情况,官网上的例子里的api就足够了
<p>Type math here: <span id="math-field"></span></p> <p>LaTeX of what you typed: <span id="latex"></span></p> <script> var mathFieldSpan = document.getElementById('math-field'); var latexSpan = document.getElementById('latex'); var MQ = MathQuill.getInterface(2); // for backcompat var mathField = MQ.MathField(mathFieldSpan, { spaceBehavesLikeTab: true, // configurable handlers: { edit: function() { // useful event handlers latexSpan.textContent = mathField.latex(); // simple API } } }); </script>
这里MathField传入的第一个参数是需要实时展示公式的input框(dom),每次输入完都会触发handlers里的edit,如果需要获取输入内容,例如在答题时,就要在这里拿结果
三、MathJax展示数学公式
举例:在我们的业务中,公式编辑器返回的LaTex公式是这样的
<p><span class="math-tex">\(x\le y\pm3\)</span></p>
而它实际代表的公式是这样的:
MathJax就可以帮助我们前端把前面这行代码转换为能够展示的公式,并且这个公式还不是不好控制的图片形式,而是一段html代码
MathJax是一款运行在浏览器中的开源数学符号渲染引擎,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。目前,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言。
MathJax根据特殊的分隔符来识别公式区域,并且根据不同的分隔符将公式展示模式分为inline(不单独占一行)和displayed(占一行),这一点可以通过window.MathJax.Hub.Config的配置信息来看一下:
window.MathJax.Hub.Config({ showProcessingMessages: false, //关闭js加载过程信息 messageStyle: "none", //不显示信息 jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [ ["$", "$"], ["\\(", "\\)"] ], //行内公式选择符 displayMath: [ ["$$", "$$"], ["\\[", "\\]"] ], //段内公式选择符 skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"] //避开某些标签 }, "HTML-CSS": { availableFonts: ["STIX", "TeX"], //可选字体 showMathMenu: false //关闭右击菜单显示 } });
我们可以看到inlineMath所对应的两种标识和displayMath对应的两种标识
MathJax可以根据自己的规则将LaTex公式很好的翻译展示,包括一些复杂的矩阵、方程组、连分数都可以进行展示,如果想看一下具体有哪些对应规则可以参考这篇文章(https://www.cnblogs.com/linxd/p/4955530.html),实际应用中,我们可以把这个工作托管给MathJax
四、MathJax的使用和展示效果
这里采用的示例是vue框架下
1. 首先,在入口文件index.html中引入MathJax,我在项目中引用的是集团上传的CDN链接,不方便放在这里,在网上找了一个,如果不能用的话再搜一搜
<script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
注:这里要放在index.html的body标签内
2. 书写配置js文件(mathConfig.js)
let isMathjaxConfig = false; //用于标识是否配置 const initMathjaxConfig = () => { if (!window.MathJax) { return; } window.MathJax.Hub.Config({ showProcessingMessages: false, //关闭js加载过程信息 messageStyle: "none", //不显示信息 jax: ["input/TeX", "output/HTML-CSS"], tex2jax: { inlineMath: [ ["$", "$"], ["\\(", "\\)"] ], //行内公式选择符 displayMath: [ ["$$", "$$"], ["\\[", "\\]"] ], //段内公式选择符 skipTags: ["script", "noscript", "style", "textarea", "pre", "code", "a"] //避开某些标签 }, "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 };
初始化时页面isMathjaxConfig为false,证明还没配置mathJax,此时进行initMathjaxConfig配置,等待mathJax配置完成后,调用MathQueue进行指定位置的公式渲染
3. 在需要展示公式的vue文件内引入配置js
import mathConfig from "../../utils/mathConfig";
4. 在页面加载完成后进行公示渲染
mounted() { if (!mathConfig.isMathjaxConfig) { //判断是否初始配置,若无则配置。 mathConfig.initMathjaxConfig(); } mathConfig.MathQueue("组件id"); //传入组件id,让组件被MathJax渲染 },
编辑器返回的内容是
展示出来是这样的
对应的元素是这样的
可以看到,其实这里mathJax给我们生成了一堆东西来展示这一个很短且简单的公式,但是从头到尾都没有用到img标签