做一個 React 項目的時候,想在網頁上渲染數學公式,不想用別人封裝好的 React 組件,採用動態加載的方式直接渲染 DOM。
Mathjax@3 做了很大的更新,使用方式也和 2.x 版本不同。
React 動態加載 js#
首先需要知道的一件事就是如何動態加載 js,用 js 將一個新的 script 節點掛載到 dom 上即可。
創建一個 dom 元素 script
,設置 src
屬性為要加載的鏈接,然後將節點添加到 body 元素內。
封裝成函數如下,只需要傳入需要加載的 js 鏈接,然後使用 .then
方法進行後續操作。
export const loadJS = (url: string) =>
new Promise(function (resolve, reject) {
const script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.body.appendChild(script);
script.onload = function () {
resolve(`success: ${url}`);
};
script.onerror = function () {
reject(Error(`${url} load error!`));
};
});
在需要使用的地方:
loadJS(url)
.then(() => {
// do something
})
.catch(() => {
// do something
});
[email protected] 版本#
先給出參考的官方鏈接,本文講的可能不太清楚。
- Loading and Configuring MathJax
https://docs.mathjax.org/en/v2.7-latest/configuration.html - Loading MathJax Dynamically
https://docs.mathjax.org/en/v2.7-latest/advanced/dynamic.html - Modifying Math on the Page
https://docs.mathjax.org/en/v2.7-latest/advanced/typeset.html
加載了 mathjax 之後,我們只要在合適的時機讓 mathjax 渲染 dom 即可。
舉個例子:
componentDidMount() {
const mathjaxUrl = 'https://cdn.bootcss.com/mathjax/2.7.4/MathJax.js?config=TeX-AMS_CHTML';
loadJS(mathjaxUrl).then(() => {
this.showMathjax();
});
}
componentDidUpdate () {
if (!(window as any).MathJax) {
(window as any).MathJax.Hub.Queue(['Typeset', (window as any).MathJax.Hub, ReactDOM.findDOMNode(this)]);
}
}
showMathjax = () => {
if ((window as any).MathJax) {
(window as any).MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$', '$']],
displayMath: [['$$', '$$']],
skipTags: ['script', 'noscript', 'style', 'textarea', 'code', 'a'],
},
CommonHTML: {
scale: 120,
linebreaks: { automatic: true },
},
'HTML-CSS': { linebreaks: { automatic: true } },
SVG: { linebreaks: { automatic: true } },
TeX: { noErrors: { disabled: true } },
});
} else {
setTimeout(this.showMathjax, 1000);
}
};
2.x 的版本,我們要使用 Mathjax.Hub.Config
來配置,這幾個配置看起來也很好懂,tex2jax
中設置了在什麼字符包裹的時候渲染數學公式。
設置了行內公式用 $...$
包裹,多行公式用 $$...$$
來包裹,對於什麼什麼標籤內的則不渲染。
然後就是設置好幾種模式下渲染的表現怎麼樣,上面我們加載的 js 時候後面有一個 query ?config=TeX-AMS_CHTML
,說明我們加載的是 CHTML 的配置,各種配置顯示效果不同。參見 https://docs.mathjax.org/en/v2.7-latest/config-files.html
Mathjax
加載好之後就會渲染頁面,但是對於單頁面應用來說, Mathjax
並不會在頁面 DOM 更新的時候重新渲染,我們需要使用 MathJax.Hub.Queue(['Typeset', MathJax.Hub, ReactDOM.findDOMNode(this)]);
來讓 Mathjax
手動渲染 DOM。添加在 componentDidUpdate
中即可。
mathjax@3 版本#
同樣給出官方文檔鏈接:
- Configuring MathJax
http://docs.mathjax.org/en/v3.0-latest/options/index.html - MathJax in Dynamic Content
http://docs.mathjax.org/en/v3.0-latest/advanced/typeset.html
3 的版本 Mathjax
的加載,配置方式都有不同。
Upgrading from v2 to v3: http://docs.mathjax.org/en/latest/upgrading/v2.html
加載時可以直接加載不同配置的 js,不需要再使用 ?config=xxx
了,比如說加載 https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js
。
Mathjax.Hub
方法被移除,現在設置配置只需要給 window.Mathjax
賦值一個配置對象即可。
官方還提供一個一鍵轉換配置的鏈接: MathJax Configuration Converter
還是給出我的配置:
(window as any).MathJax = {
tex: {
inlineMath: [['$', '$']],
displayMath: [['$$', '$$']],
},
options: {
skipHtmlTags: ['script', 'noscript', 'style', 'textarea', 'code', 'a'],
},
chtml: {
scale: 1.2,
},
startup: {
ready: () => {
(window as any).MathJax.startup.defaultReady();
(window as any).MathJax.startup.promise.then(() => {
console.log('MathJax initial typesetting complete');
});
},
},
};
Mathjax
腳本加載好之後會讀取 window.Mathjax
為配置並且替換為 Mathjax
對象,然後你就可以調用相關函數了。
Mathjax
初始化時會調用配置中的 startup.ready
方法,你可以在裡面做一下提示或者其他配置。
還是那個問題,Mathjax
在 DOM 更新時不會重新渲染,需要使用 MathJax.typesetPromise()
方法。也在 componentDidUpdate
中設置即可。
componentDidUpdate() {
const MathJax = (window as any).MathJax;
if (MathJax) {
MathJax.typesetPromise && MathJax.typesetPromise();
}
}
這個方法是異步方法,還有一個相同功能的同步方法: MathJax.typeset()
。