1. <dd id="erndk"></dd>
                1. 基于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}.$$給識別成公式

                  x = {-b \pm \sqrt{b^2-4ac} \over 2a}.

                  (掘金編輯器也支持了latex~,點贊)

                  尋找開發思路,鎖定目標

                  在google上初步的篩查,鎖定了兩個插件:katexMathJax。他們都是渲染公式的工具,看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其實是有兩種識別公式的方式。

                  1. 第一種就是我剛剛說的全局配置,配置好之后,腳本會在網頁中尋找符合條件的公式符號(比如被包裹在$中的內容),并把它編譯。

                  點擊查看demo效果以及對應html代碼

                  1. 第二種是將用戶在表單中輸入的公式,用事件觸發的方式,比如點擊按鈕,再去編譯輸入框中的內容,返回html(如知乎的形式)

                  點擊查看demo效果以及對應html代碼

                  尤其第一種,看上去非常簡單省心。

                  引入資源(我為了防止國外鏡像不穩定,把資源下載到了本地),全局配置,幾分鐘就搞定了。然后打開頁面。emmm...沒效果。由于太簡單了,甚至都不知道問題出在哪里。。

                  寫了個靜態頁面,同樣的配方,是有效果的,看來問題是出在vue上啊。初步猜測,是因為vue的數據都是渲染上去的,所以MathJax腳本加載的時候,頁面還沒有內容。等內容有了之后,腳本早執行完了,所以導致沒有效果。不過也是瞎猜的,google了其他人有沒有遇到同樣的問題,就遇到了開頭我所說的,網上蜜汁全是2.7.5版本的實現方式,有一個window.MathJax.Hub.Queue(["Typeset", MathJax.Hub])方法好像是實現了“重載腳本”的效果。然而,我現在3.0.0版本,這個方法已經undefined了....

                  再次陷入僵局。

                  期間嘗試過很多其他思路,當然現在看來都是在走彎路了。

                  1. 想在編輯框加一個按鈕,退而求其次,用輸入框的方式去生成公式。但是公式編譯后的html又長又臭,就這樣插入markdown顯然不好。
                  2. 嘗試剛剛提到的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

                  贊(1)
                  關注微信小程序
                  程序員編程王-隨時隨地學編程

                  掃描二維碼或查找【程序員編程王】

                  可以隨時隨地學編程啦!

                  技術文章導航 更多>
                  国产在线拍揄自揄视频菠萝

                        1. <dd id="erndk"></dd>