美文网首页
vue+MathJax 让前端支持数学公式

vue+MathJax 让前端支持数学公式

作者: 文芬 | 来源:发表于2020-11-20 11:05 被阅读0次

    1.开发背景

    目前在使用vue+elementui做一个考试管理系统,在做学生考试页面时需要用到数学公式,但是后台解析出来后不是图片,而且如果是图片的话放在题目里很怪,所以需要使用到MathJax去解析后台传过来的公式

    后台返回的数据:

    <math xmlns="http://www.w3.org/1998/Math/MathML"><mtext>minimum at&#xA0;</mtext><mi>f</mi><mo>(</mo><mn>0</mn><mo>,</mo><mo>&#x22EF;</mo><mo>,</mo><mn>0</mn><mo>)</mo><mo>=</mo><mn>0</mn><mo>+</mo><mi>n</mi><mi>o</mi><mi>i</mi><mi>s</mi><mi>e</mi></math>
    

    2.使用MathJax

    2.1 引入CDN

    在使用MathJax之前,需要通过CDN引入, 在<body>标签中添加:

    <script type="text/javascript" async src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML"></script>
    

    注意 :如果是国内的话建议使用下面的链接

    <link rel="dns-prefetch" href="//cdn.bootcss.com" />
    <script type="text/javascript" src="//cdn.bootcss.com/mathjax/2.7.0/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    

    2.2 配置MathJax

    MathJax的配置封装成一个函数:
    详细配置可以参考MathJax官网,放在了文档最后。

    let isMathjaxConfig = false; // 防止重复调用Config,造成性能损耗
    
    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; // 
    };
    

    项目中基本全局用到,我是全局配置

    <script type="text/x-mathjax-config">
                MathJax.Hub.Config({
                    tex2jax: {inlineMath: [['$','$'], ['\(','\)']]}
                });
            </script>
    

    2.3 使用MathJax渲染

    MathJax提供了window.MathJax.Hub.Queue来执行渲染。在执行完文本获取操作后,进行渲染操作:

    if (isMathjaxConfig === false) { // 如果:没有配置MathJax
      initMathjaxConfig();
    }
    
    // 如果,不传入第三个参数,则渲染整个document
    // 因为使用的Vuejs,所以指明#app,以提高速度
    window.MathJax.Hub.Queue(["Typeset", MathJax.Hub, document.getElementById('app')]);
    

    你也可以在组件中指定Id名称去渲染公式

    这一步不一定用传入id的方式,也可以传入标签name用getElementByName来获取组件对象,渲染的细节点比较多,可以参考下面模式

    //传入组件id/name/class,让组件被MathJax渲染
    const MathQueue = function (elementId) {
        if (!window.MathJax) return;
    
        var timer = setTimeout(function(){
            // window.MathJax.Hub.Queue(["Typeset", window.MathJax.Hub, document.getElementById(elementId)]); //这里可以用原生的js调用name,class,id。
            window.MathJax.Hub.Queue(["Typeset", MathJax.Hub, () => {
                let mathdivs = $('.'+elementId).find(".mathDivIndex");
                for(let i=0; i<mathdivs.length; i++){
                    return mathdivs[i]
                }
            }]);
            clearTimeout(timer)
        }, 50)
    };
    

    2.4 修改默认样式

    MathJax默认样式在被鼠标focus的时候,会有蓝色边框出现。对于超长的数学公式,x方向也会溢出。
    添加以下样式代码,覆盖原有样式,从而解决上述问题:

    /* MathJax v2.7.5 from 'cdnjs.cloudflare.com' */
    .mjx-chtml {
      outline: 0;
    }
    .MJXc-display {
      overflow-x: auto;
      overflow-y: hidden;
    }
    

    3. 注意事项

    3.1 不要使用npm

    尽量不要使用npm,会出现很多未知问题
    如果是vue项目,直接在public文件夹的index文件的头部或者尾部添加<script>标签(CDN链接)

    // 如果不是引入的cdn链接,可以这么使用放本地
    $ npm install mathjax@2.7.5 --save // 表明版本号
    <script src="/node_modules/mathjax/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
    

    3.2多处使用

    如果在很多地方都需要用到MathJax,可以在单独把配置项封装成一个JS文件,然后在main.js文件中导入并注册为全局JS

    JS文件(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"] //避开某些标签
            },
            "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)]);//这里可以用原生的js调用name,class,id。
    };
    export default {
      isMathjaxConfig,
      initMathjaxConfig,
      MathQueue,
    }
    

    main.js文件中添加:

    import globalVariable from './assets/js/globalVariable'
    Vue.prototype.commonsVariable = globalVariable;
    

    使用:如果是vue就在mounted钩子函数中写

    this.$nextTick(function () { //这里要注意,使用$nextTick等组件数据渲染完之后再调用MathJax渲染方法,要不然会获取不到数据
        if(this.commonsVariable.isMathjaxConfig){//判断是否初始配置,若无则配置。
            this.commonsVariable.initMathjaxConfig();
        }
        this.commonsVariable.MathQueue("question-id");//传入组件id,让组件被MathJax渲染
    })
    

    3.3动态数据

    在SPA单页应用中,数据是通过Ajax获取的。此时,需要在数据获取后,再执行渲染

    如果习惯es5,可以在回调函数中调用window.MathJax.Hub.Queue。但是更推荐es6,配合Promiseasync/await来避免“回调地域”。

    3.4第一次不显示问题,刷新后显示

    这种何况应该是网速慢所以可以加一个定时器

    setTimeout(() => {
                this.$nextTick(function () { //这里要注意,使用$nextTick等组件数据渲染完之后再调用MathJax渲染方法,要不然会获取不到数据
                    if(this.commonsVariable.isMathjaxConfig){//判断是否初始配置,若无则配置。
                        this.commonsVariable.initMathjaxConfig();
                    }
                    this.commonsVariable.MathQueue("question-id");//传入组件id,让组件被MathJax渲染
                })
            },1000)
    

    3.4 版本问题

    对于不同版本或者不同CDN的MathJax,第二部分的样式覆盖的class名称不同。比如在cdnbootv2.7.0版本中,样式覆盖的代码应该是下面这段:

    /* MathJax v2.7.0 from 'cdn.bootcss.com' */
    .MathJax {
      outline: 0;
    }
    .MathJax_Display {
      overflow-x: auto;
      overflow-y: hidden;
    }
    

    4. 更多资料

    相关文章

      网友评论

          本文标题:vue+MathJax 让前端支持数学公式

          本文链接:https://www.haomeiwen.com/subject/npkdiktx.html