让你的网页可以同时显示html和Latex数学公式—— ReactHtmlParser 和 React Mathjax

目录

1. ReactHtmlParser

1.1 功能

1.2 使用方法

2. React MathJax

2.1 功能

2.2 搭配react-mathjax-preview

2.3 搭配react-mathjax

3. 总结


1. ReactHtmlParser

1.1 功能

ReactHtmlParser可以将一个以html格式编写的字符串解析成react组件并渲染到屏幕上。这对于我们在网页上发表文章是很有帮助的,每次发布一篇新的文章,可以直接将其按照html的语法编辑并作为ReactHtmlParser的输入参数,render之后就可以在屏幕上看到自己写的内容了。

1.2 使用方法

用之前,别忘了要先安装react-html-parser

npm install react-html-parser
# or 
yarn add react-html-parser

安装好就可以直接import ReactHtmlParser来解析html字符串啦。

咱们先写一个Article的React组件,它接受一个名为article的属性,并渲染article的内容。

import React from 'react';
import ReactHtmlParser from 'react-html-parser';
 
class Article extends React.Component {
  constructor(props){
    super(props);
  }
  render() {
    const article = this.props.article;
    return (
    <div>
       <h1>
           {article.title}
       </h1>
       <div>
            {ReactHtmlParser(article.content)}
       </div>
    </div>
    )
  }
}

我们的文章的content应该是一个以html语法编写的字符串,例如下面这样:

const article = {
      "title": "General Regulations for Flying a Drone in Canada",
      "content": 
          `
          <img src="/images/1.png" width="25%"/>
          <br> 
          <p>What is the result of following?</p>
          <p>The following rules apply to all drone operations:</p>
          <p>&middot; All drones that weigh 250 g and 25 kg should be documented with <u><a href="https://tc.canada.ca/en">Transport Canada.</a></u></p>
          <p>Pilots have to mark their drones with their registration digits prior they fly.</p>
          <p>&middot; All pilots of drones that weigh between 250 g and 25 kg should earn a drone pilot certification.</p>
          <p>&middot; Fly your drone as long as you can see it at all times.</p>
          `
}

当我们需要显示这篇文章时,只需要简单的用React渲染一下即可:

const root = ReactDOM.createRoot(
  document.getElementById('root')
);

root.render(<Article article={article} />);

 在yarn start之后,你应该在本地的localhost上看到如下画面:

2. React MathJax

2.1 功能

React Mathjax是为了弥补React Html Parser无法解析数学公式,只能解析html tag (如<div><p><a>) 等的缺点,而被开发出来的。但是它在render数学公式的同时,又无法识别html的语法。因此,如果用MathJax官网上的添加<script>来显示数学公式的办法是行不通的,因为咱们这里的输入内容不是html,而是以html格式编写的字符串。

因此,如果要让你的网页能够解析html字符串的同时,也能解析其中的数学公式,我们需要将React Html Parser和React Mathjax结合起来使用。根据具体使用工具的不同,有以下两种方法.

2.2 搭配react-mathjax-preview

react-mathjax-preview中的mathjax可以完美的根据\$$...\$$和$...$来分别显示段间公式和行内公式。但是React Html Parser并不知道哪一段会出现公式,因此,我们需要DIY一个Parser来将数学部分和普通的html部分分开,并用对应的工具去解析他们。

首先,别忘了安装react-mathjax-preview

yarn add react-mathjax-preview

因为mathjax无法识别html tag,所以我们可以自创一个数学tag叫<mathtype>来标记哪些部分出现了数学公式。先用DOMParser对html string进行初步解析,它会将每个满足<...></...>的字符串认定为一个tag。接着我们对每一个node进行判断,如果node中包含我们自创的'mathtype',说明此部分内容需要用mathjax来解析,将其的type定义为'math',并将html字符串传到变量'html',保存至数组itemsArray中。但是由于mathjax本身并不能识别tag,因此只需要将这部分字符串的innerHTML传过去(即只取中间内容),而不是outerHTML。

接着我们对分类好的itemsArray进行一个遍历,如果type是math,调用MathJax,否则,调用ReactHtmlParser。

代码如下:

import MathJax from 'react-mathjax-preview';
import ReactHtmlParser from 'react-html-parser';

const Parser = ({ mString }) => {
    const iparser = new DOMParser();
    const parsedHtml = iparser.parseFromString(mString, 'text/html');
    const itemsArray = [];
    if (!parsedHtml || !parsedHtml.body) return null;

    parsedHtml.body.childNodes.forEach(item => {
        let type = 'normal';
        if (!item.outerHTML) return;
        if (item.outerHTML.includes('mathtype')) {
            type = 'math';
            itemsArray.push({ type, html: item.innerHTML })
        }else{
            itemsArray.push({ type, html: item.outerHTML });
        }
    });

    return (
        <div>
            {itemsArray.map((item) =>
                item.type === 'math' ? (
                    <MathJax math={item.html} />
                ) : (
                    <div>{ReactHtmlParser(item.html)}</div>
                )
            )}
        </div>
    );
};

下面以一段html字符串位例。react-mathjax-preview会自动根据单$和双$识别输入参数中哪部分不需要数学表示,那部分需要行内数学显示,哪部分需要段间数学显示。

const article = {
    "title": "An Example of Using React Html Parser to Render",
    "content": 
    `       
        <p> This article is a demo. </p>
        <mathtype>
            In this article, we will introduce the interesting problem of pose estimation for drones, and share some of the
            research we have done in this area. The pose of a drone can serve as an important feature for us to further analyze
            the high-level behavior of the drone, such as its distance and flight trajectory. The pose refers to the angle of
            rotation of the drone on three axes, relative to the camera position. The drone displayed below has a pose angle of
            (0,0,0):
            $$a+b=c\\quad\\quad\\quad(1)$$
            $$A^2+\\mathbf{B}^2=C\\quad\\quad\\quad(2)$$
            $$\\lim_{x \\to \\infty} e^{-x} = 1\\quad\\quad\\quad(3)$$ 
        </mathtype>
        
        <mathtype>
        Consider the two-dimensional problem in which the sensors and the target drone are all in the same horizontal 
        plane. Let $(x,y)$ denote the position of the drone, and let $(x_i,y_i)$ denote the position of sensor $i$, for i = 1,2,…,N; where N is the number of sensors in the detection network. 
        In terms of these positions, the distance differences relative to sensor 1 are $$\\sum_{i=1}^n i^3=((n(n+1))/2)^2\\quad\\quad\\quad(4)$$
        </mathtype>
        `
  }

这部分字符串中,ReactHtmlParser会负责解析<p>,而MathJax负责解析<mathtype>中的内容。下面,我们要把Article中的ReactHtmlParser换成我们自定义的Parser:

class Article extends React.Component {
  constructor(props){
    super(props);
  }
  render() {
    const article = this.props.article;
    return (
    <div>
       <h1>
           {article.title}
       </h1>
       <div>
            <Parser mString = {article.content} />
       </div>
    </div>
    )
  }
}

const root = ReactDOM.createRoot(
  document.getElementById('root')
);

root.render(<Article article={article} />);

显示出来的内容如下:

 效果还是很完美的。

注意: 在Javascript中,符号'\'是特殊符号,所以在编辑latex的时候,一切latex中的特殊符号不要使用'\'而是使用'\\',例如加粗\textbf{}换成\\textbf{}

2.3 搭配react-mathjax

react-mathjax-preview已经很久不更新了,有些环境中,可能出现未知错误,导致网页无法渲染。替代方法是使用react-mathjax中的MathJax。

先安装react-mathjax。其使用方法比react-mathjax-preview要复杂一点:

import MathJax from 'react-mathjax'

const tex = `f(x) = \\int_{-\\infty}^\\infty
    \\hat f(\\xi)\\,e^{2 \\pi i \\xi x}
    \\,d\\xi`
 
module.exports = () => {
    return (
        <MathJax.Provider>
            <div>
                This is an inline math formula: <MathJax.Node inline formula={'a = b'} />
                And a block one:
 
                <MathJax.Node formula={tex} />
            </div>
        </MathJax.Provider>
    );
}

对于行内公式,用<MathJax.Node inline formula={/*your formula*/}/>,段间公式,用<MathJax.Node formula={/*your formula*/}。但是它会把所有输入内容渲染成数学公式,而无法像react-mathjax-preview那样根据$符号来识别。因此,我们做的准备工作要复杂一点。但是基本思路和2.2是一样的。

我们自创两个tag, 一个叫<mathinline>,另一个叫<mathblock>,分别为行内公式和段间公式的html tag。后者简单,直接把inner HTML喂给MathJax就行了,前者要复杂一点,需要我们手动将公式部分和普通文字部分区别出来。为了和Latex保持一致,我们就用$号来包裹公式。这样,我们对<mathinline>中的内容进行以$符号的split,得到的数组偶数位为普通文字,奇数位为行内公式。

具体代码如下:

const Parser = ({ mString }) => {
    const iparser = new DOMParser();
    const parsedHtml = iparser.parseFromString(mString, 'text/html');
    const itemsArray = [];
    if (!parsedHtml || !parsedHtml.body) return null;

    parsedHtml.body.childNodes.forEach(item => {
        let type = 'normal';
        if (!item.outerHTML) return;
        if (item.outerHTML.includes('mathblock')) {
            type = 'mathblock';
            itemsArray.push({ type, html: item.innerHTML});
        }else if (item.outerHTML.includes('mathinline')){
            type = "mathinline";
            let tempItem = item.innerHTML;
            itemsArray.push({ type, html: tempItem.split("$$") });
        }else{
            itemsArray.push({ type, html: item.outerHTML });
        }
    });
    console.log(itemsArray)

    return (
        <div>
            {itemsArray.map((item) =>
                item.type === 'mathblock' ? (
                    <MathJax.Provider>
                        <div>
                            <MathJax.Node formula={item.html} />
                        </div>
                    </MathJax.Provider>

                ) : (
                item.type === 'mathinline' ? (
                    <MathJax.Provider>
                        <p>
                        {item.html.map((section, index) => {
                            return index % 2 == 1 ? <MathJax.Node inline formula={section}/> : section
                        })}
                        </p>
                    </MathJax.Provider>   
                ) : ReactHtmlParser(item.html))
            )}
        </div>
    );
};

比较复杂地方就在于需要对mathinline的数组进行一个循环,奇数为用行间公式输出,否则正常输出,并保证在一个段落中<p>。范例就不举了。可以仿照2.2来试验。注意这些math的tag都是我们自己命名的,你可以设计自己的名称,但注意不要太短。

3. 总结

本文主要描述了两种搭配mathjax来进行latex输出的方法,但它们只适用于React对纯字符串的解析。如果只有一篇文章,不需要批量编辑,直接用一个React component去描述这篇文字,并用MathJax官网上描述的在html的<head>中加<script>就可以了。

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值