前端实现方程式(Vue中使用MathJax)
MathJax 在线工具 [https://www.codecogs.com/latex/eqneditor.php]数学公式分为行内公式和跨行公式,当然都需要支持和渲染。我准备了3条公式,分别是行内公式、跨行公式和超长的跨行公式:\alpha+\beta=\gamma$$$\alpha+\beta=\gamma$$$$\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}
MathJax 在线工具 [https://private.codecogs.com/latex/eqneditor.php]
数学公式分为行内公式和跨行公式,当然都需要支持和渲染。
我准备了3条公式,分别是行内公式、跨行公式和超长的跨行公式:
\alpha+\beta=\gamma$
$$\alpha+\beta=\gamma$$
$$\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}\int_{0}^{1}f(x)dx \sum_{1}^{2}$$
1、前言
最近公司的一个项目需求是在前端显示Latex转化的数学公式,经过不断的百度和测试已基本实现。现在此做一个记录。
2、MathJax介绍
MathJax是一款运行在浏览器中的开源的数学符号渲染引擎,使用MathJax可以方便的在浏览器中显示数学公式,不需要使用图片。目前,MathJax可以解析Latex、MathML和ASCIIMathML的标记语言。(Wiki)
3、步骤
3.1、引入MathJax
我们通过在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>
3.2、创建方法配置MathJax
引入MathJax之后就需要我们配置MathJax了,这是为了让MathJax可以通过配置的标识来识别要被转化的数学公式。这一步我是参考了这位大佬的写法《MathJax: 让前端支持数学公式》的写法,具体如下。
(1)创建globalVariable.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
};
export default {
isMathjaxConfig,
initMathjaxConfig,
}
这一步其实也可以使用直接配置的方法,这里就不记录了,具体可以看《前端整合MathjaxJS的配置笔记》这块。
(2)在main.js中将globalVariable.js引入,这样就可以在项目内任何地方都可以使用了。
import globalVariable from './components/globalVariable/globalVariable'
Vue.prototype.commonsVariable = globalVariable;
3.3、创建方法渲染公式
到了关键的一步了,这里的原理就是通过传入组件对象或者标签id再用MathJax的window.MathJax.Hub.Queue来渲染组件来转换公式。具体步骤如下。
(1)创建在globalVariable.js中创建渲染方法。
const MathQueue = function (elementId) {
if (!window.MathJax) {
return;
}
window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, document.getElementById(elementId)]);
};
export default {
isMathjaxConfig,
initMathjaxConfig,
MathQueue,
}
这一步不一定用传入id的方式,也可以传入标签name用getElementByName来获取组件对象。
(2)再需要渲染的页面中调用方法即可。当vue数据改变的时候,我们使用$nextTick等待组件数据渲染完成后,再将组件id传入方法中,让mathjax来渲染公式。
<template>
<div>
<div id="question-id">
<div class="swappy-radios" >
<div name="titleDiv">
<h3> 题目:{{this.questionToOptions.Question.body}}</h3> //这里的questionToOptions.Question.body传入的就是Latex公式
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {}
},
data() {
return {
rawHtml:'',
heightString: 'height: 500px;',
questionToOptions: this.value,
answer: '',
imgIndex: 0,
};
},
methods: {
},
watch: {
//监听prop传的value,如果父级有变化了,将子组件的myValue也跟着变,达到父变子变的效果
//这里看需求,若不使用监听,直接放在axios请求方法中也是可以的
value(value) {
// titleDiv
this.questionToOptions = value;
this.answer = '';
this.$nextTick(function () { //这里要注意,使用$nextTick等组件数据渲染完之后再调用MathJax渲染方法,要不然会获取不到数据
if(this.commonsVariable.isMathjaxConfig){//判断是否初始配置,若无则配置。
this.commonsVariable.initMathjaxConfig();
}
this.commonsVariable.MathQueue("question-id");//传入组件id,让组件被MathJax渲染
})
},
answer(newVal) {
this.$emit('trouble', newVal)
}
},
mounted() {
}
}
</script>
3.4、出现错误和解决方法
本来到这里就应该结束了,但是在value数据连续改变的情况情况下MathJax渲染过得数据会不断堆积,造成错误
对于这个错误我没有找到一个好的解释,若有知道的大佬还请指出,多谢了。
我自己最后猜测是MathJax对于同一个组件渲染不是以刷新的方式,而是在上一次渲染的基础上添加数据进行渲染。所以我想到了,在下次渲染之前先将上一个组件内部带有数学公式清空,然后再进行渲染。具体方式如下:
<template>
<div>
<div id="question-id">
<div class="swappy-radios" >
<div name="titleDiv">
<div v-html="rawHtml"></div>//这里改为用v-html,通过html字符串来每次生成html代码,从而达到刷新组件的效果。
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
value: {}
},
data() {
return {
rawHtml:'',
heightString: 'height: 500px;',
questionToOptions: this.value,
answer: '',
imgIndex: 0,
};
},
methods: {
},
watch: {
value(value) {
// titleDiv
this.questionToOptions = value;
this.rawHtml = '<h3>题目:'+this.questionToOptions.Question.body +'</h3>';//将公式转化为html字符串存入。
this.answer = '';
this.$nextTick(function () {
if(this.commonsVariable.isMathjaxConfig){
this.commonsVariable.initMathjaxConfig();
}
this.commonsVariable.MathQueue("question-id");
})
},
answer(newVal) {
this.$emit('trouble', newVal)
}
},
mounted() {
}
}
</script>
更多推荐
所有评论(0)