基于vue渲染Latex數學公式(simplemde-editor)
如意同學 2020/3/20 11:01:29
網絡關于vue + mathjax的中文教程和博客都弱爆了,基本都是2年前MathJax 2.7.5版本的使用反復在被炒冷飯,甚至在2020年2月份的文章中還有人在引用。許久不寫前端文章的我忍不出山了。
說句題外話,在我當年想要入門前端的時候,互聯網上的學習總結一抓一大把,各種項目坑都可以找到,而且還都有模有樣。當我現在想要入門深度學習算法的時候,卻發現學習資源,尤其是優質的中文資源就沒那么好找了。曾經跟朋友聊過這個話題,當時朋友開玩笑說,前端工程師都太閑了,日常解決個大bug都可以去寫總結篇文章。在掘金其實也可以發現這一點,前端社區非?;钴S,深度學習領域的板塊就顯得相對冷清。
活躍當然是好事,只不過還是希望能夠有更多真正原創內容的產出,從而能幫到更多的人吧。
本文從實際項目出發,從一開始問題都不知道怎么定義,基本一竅不通,到現在基本解決了實際中遇到的問題,梳理了整個開發思路。
本文提到的Mathjax版本是3.0.0
項目需求
需求很簡單,需要讓我們的markdown編輯器支持數學公式latex的寫法,在發表后公式也可以正常顯示。
例如,把$$x = {-b \pm \sqrt{b^2-4ac} \over 2a}.$$
給識別成公式
(掘金編輯器也支持了latex~,點贊)
尋找開發思路,鎖定目標
在google上初步的篩查,鎖定了兩個插件:katex
和MathJax
。他們都是渲染公式的工具,看demo是都可以做到輸入latex,輸出html,展示為數學公式。
mathJax是公式渲染的鼻祖了,歷史悠久,但依然在持續更新。不過好多跳轉鏈接都失效了
而katex后來者居上,star更多,官網更美觀,而且也展示了katex和mathjax的渲染速度對比
所以一開始我就選擇了katex進行開發。
開發探索階段
1. katex與simplemde的糾纏
我目前使用的編輯器是simplemde
,katex的英文官網給出的實例寫法是這樣
var html = katex.renderToString("c = \\pm\\sqrt{a^2 + b^2}", { throwOnError: false }); 復制代碼
非常簡潔,也沒有更多的demo。我的思路是,把markdown中的公式找出來,用這個方法轉化一下再加到正常的渲染結果里去,應該就可以了吧?
simplemde官網給出了一個方法previewRender
,可以用于在預覽生效前自定義一些渲染效果。

這樣一來,問題就變成了,把公式從markdown中找出來,再把公式塞回html里去
。
我主要是想通過正則匹配去做這件事情,查資料查了不少時間,就是匹配不出來,更別說塞回去了(我討厭正則)。
中間去吃了個晚飯,中斷了一下前進的腳步,回來后鬼使神差打開了MathJax的官網...
這一看,就發現了神奇的大陸,在demo中,mathJax只要引入全局資源和全局配置,就能自動把全站的公式都識別出來,這樣不管是在預覽區還是發表之后,就一步到位全部識別了。果然姜還是老的辣。
2. 轉而探索MathJax
深入地看了MathJax的Gihub和官方文檔之后,了解到mathJax其實是有兩種識別公式的方式。
- 第一種就是我剛剛說的全局配置,配置好之后,腳本會在網頁中尋找符合條件的公式符號(比如被包裹在
$
中的內容),并把它編譯。
點擊查看demo效果以及對應html代碼
- 第二種是將用戶在表單中輸入的公式,用事件觸發的方式,比如點擊按鈕,再去編譯輸入框中的內容,返回html(如知乎的形式)
點擊查看demo效果以及對應html代碼
尤其第一種,看上去非常簡單省心。
引入資源(我為了防止國外鏡像不穩定,把資源下載到了本地),全局配置,幾分鐘就搞定了。然后打開頁面。emmm...沒效果。由于太簡單了,甚至都不知道問題出在哪里。。
寫了個靜態頁面,同樣的配方,是有效果的,看來問題是出在vue上啊。初步猜測,是因為vue的數據都是渲染上去的,所以MathJax腳本加載的時候,頁面還沒有內容。等內容有了之后,腳本早執行完了,所以導致沒有效果。不過也是瞎猜的,google了其他人有沒有遇到同樣的問題,就遇到了開頭我所說的,網上蜜汁全是2.7.5版本的實現方式,有一個window.MathJax.Hub.Queue(["Typeset", MathJax.Hub])
方法好像是實現了“重載腳本”的效果。然而,我現在3.0.0版本,這個方法已經undefined了....
再次陷入僵局。
期間嘗試過很多其他思路,當然現在看來都是在走彎路了。
- 想在編輯框加一個按鈕,退而求其次,用輸入框的方式去生成公式。但是公式編譯后的html又長又臭,就這樣插入markdown顯然不好。
- 嘗試剛剛提到的mathJax的第二種方法,把vue渲染的數據看作是表單內容,仿照demo,直接把整個markdown數據扔進
MathJax.tex2chtmlPromise()
函數里。這個方法在內容中只有公式的時候表現優異,還讓我激動了一把。結果一加入其他dom元素就歇菜,整個dom被重組,樣式也全部丟失。
3. 文檔還是硬道理
google無果,能想到的方法也都試了,最終還是回歸文檔,看看有什么被我忽略的方法。事實證明,只有文檔才能解決一切問題,我看到了一個Handling Asynchronous(異步處理)的方法MathJax.typesetPromise()
。

在數據渲染完成的地方,加上這個方法之后,世界就變得美好了...
- 在內容展示頁,只需要在數據返回后加上這個方法,為保證腳本在頁面渲染完成后再執行,可以稍作延遲:
ajax.get(xxx).then(res => { // 頁面渲染 settimeout(res => { MathJax.typesetPromise() }, 500) }) 復制代碼
在markdown編輯區,在預覽渲染后,執行渲染腳本,這里就用到了開始提到的simplemde的自定義渲染方法previewRender
,同樣的,為保證腳本在頁面渲染完成后再執行,可以稍作延遲。其他編輯器,只要找到類似的方法也都可以這么處理:
this.simplemde = new SimpleMDE({ { //...其他配置項 previewRender: (plainText) => { settimeout(res => { MathJax.typesetPromise() }, 500) return this.simplemde.markdown(plainText) } }, element: document.getElementById('simplemde') }) 復制代碼
想來,這個方法應該就是在廢棄2.x版本window.MathJax.Hub.Queue
之后的替代方法吧。隨后,果然如此,發現了這一頁,官網也有非常詳細的說明。(為什么不早發現呢。T_T)

之后還處理了行內公式的識別,MathJax也出了自定義的識別方法,更多的config也都能在官網上找到。
window.MathJax = { startup: { pageReady: () => { // alert(111) // 檢驗腳本首次是否加載成功 return window.MathJax.startup.defaultPageReady() } }, tags: 'all', // 為方程式編號 tagSide: 'left', // 方程式編號的位置 tex: { processEscapes: true, processEnvironments: true, // process \begin{xxx}...\end{xxx} outside math mode processRefs: true, // process \ref{...} outside of math mode inlineMath: [ ['$', '$'], ['\\(', '\\)'] ], displayMath: [ // start/end delimiter pairs for display math ['$$', '$$'], ['\\[', '\\]'] ] } 復制代碼
4. 對MathJax探索的總結與梳理
這整個探索流程花費了兩個半天的時間。個人對于MathJax的整體機制
也隨著探索的過程逐漸有了更深的了解。我覺得對于后來者,更重要的應該是解決問題的思路,而不是照搬方法。所以想在這里根據我的理解,簡單解釋一下mathjax的機制。
上文也有提到,對于MathJax來說,有兩種渲染公式的方式。我不厭其煩地再嘮叨一遍:
第一種,就是我剛剛說的全局配置。首先引入CND資源,并設置好全局配置。等頁面渲染好后,腳本開始執行,在網頁中尋找符合條件的公式符號(比如被包裹在$
中的內容),并把它編譯。
你仔細看就會發現,官網的示例都給CDN加上了async
,同步加載,也就是說,腳本會等頁面內容都加載完成后,再執行,從而保證公式正常渲染。
但是,在像vue這些數據驅動的MVC框架下,外部資源要想對dom進行渲染,那真是太天真了,async
肯定無效,這時候就需要“重新執行腳本”。在3.x版本中,也就是MathJax.tex2chtmlPromise()
方法。
第二種,是比較好理解的,和katex給出的示例類似。是將指定的公式內容,全部轉成公式格式。通??梢杂糜谟脩粼诒韱沃休斎?,用事件觸發的方式,比如點擊按鈕,再去編譯輸入框中的內容,返回html。
相比mathjax,Katex我是只是初步進行了探索,很有可能我沒有注意到,說不定它的第一種實現也是有。畢竟它官網列舉了辣么多的優點
結語
katex,mathjax,還有simplemed,全都沒有中文文檔??赡荛_發過程中如果遇到坑了,很多人第一反應都不是翻文檔(我自己也是),而是去搜索有沒有人遇到類似的問題,甚至直接去github上去提issue。
而這次經歷給我的經驗是,適可而止的google,答案都在文檔里。

關于找一找教程網
本站文章僅代表作者觀點,不代表本站立場,所有文章非營利性免費分享。
本站提供了軟件編程、網站開發技術、服務器運維、人工智能等等IT技術文章,希望廣大程序員努力學習,讓我們用科技改變世界。
[基于vue渲染Latex數學公式(simplemde-editor)]http://www.yachtsalesaustralia.com/tech/detail-120058.html
- 2022-05-19Jenkins自動構建部署vue項目到遠程Windows服務器上 騰訊工蜂(git) 一鍵打包+部署+解壓+發布(下)---jenkins的環境配置和使用
- 2022-05-19vue實現lodop打印功能--無感打印
- 2022-05-19面試之JS篇
- 2022-05-18vue axios 賦值后console可以查看到 html調用數據失敗
- 2022-05-18vue安裝
- 2022-05-18js 閉包的認知提升
- 2022-05-18gnvm:nodejs版本管理工具的使用
- 2022-05-18Golang:將日志以Json格式輸出到Kafka
- 2022-05-18js 顏色求值在區間內的RGB值_liuqing0.0的博客
- 2022-05-18vue實際項目中關于圖片的大量加載的優化及思路_liuqing0.0的博客