Angular中使用MathJax遇到的一些問(wèn)題
前言
話說(shuō)我本來(lái)是傾向于 KaTeX 的,因?yàn)槲腋杏X(jué)他很快,而且 MathJax 似乎很難配。但是大家表示對(duì)缺少功能的 KaTeX 并無(wú)好感,給我提供了一些鉆研 MathJax 的動(dòng)力。
MathJax簡(jiǎn)介
MathJax是一款運(yùn)行在瀏覽器中的開(kāi)源數(shù)學(xué)符號(hào)渲染引擎,使用MathJax可以方便的在瀏覽器中顯示數(shù)學(xué)公式,不需要使用圖片。目前,MathJax可以解析Latex、MathML和ASCIIMathML的標(biāo)記語(yǔ)言。MathJax項(xiàng)目于2009年開(kāi)始,發(fā)起人有American Mathematical Society, Design Science等,還有眾多的支持者,個(gè)人感覺(jué)MathJax會(huì)成為今后數(shù)學(xué)符號(hào)渲染引擎中的主流,也許現(xiàn)在已經(jīng)是了。
個(gè)人其實(shí)也不算鉆研,因?yàn)閷?shí)際上 MathJax 很簡(jiǎn)單,調(diào)用 MathJax.Hub.Queue(['Typeset', MathJax.Hub, this.element.nativeElement]); 就可以渲染一個(gè)元素(這個(gè) this.element.nativeElement 是從 Angular 中調(diào)用它 DOM 的語(yǔ)法),這個(gè) .Queue 實(shí)際上是 MathJax 自己實(shí)現(xiàn)的回調(diào)格式,語(yǔ)法非常清奇,參數(shù)個(gè)數(shù)不定,每個(gè)都是數(shù)組,代表一個(gè)回調(diào),順序執(zhí)行。比如這個(gè) ['Typeset', MathJax.Hub, this.element.nativeElement] ,第一個(gè)元素是方法名,第二個(gè)元素是 this ,之后的元素都是參數(shù)……
我們可以看到這個(gè)就相當(dāng)于執(zhí)行 MathJax.Hub.Typeset(this.element.nativeElement) ,那為啥不執(zhí)行這個(gè)?因?yàn)檫@方法是同步的,會(huì)導(dǎo)致頁(yè)面十分卡。于是 MathJax 就自己封裝了一個(gè)異步隊(duì)列(它的 API 可能幾百年沒(méi)改了)
我們說(shuō)回 Angular。因?yàn)橐?markdown,我的思路是用 marked 封裝一個(gè) directive。那么我們就應(yīng)該在 marked 渲染完成之后用 MathJax 去 Typeset 這個(gè)組件。但真的這樣做了,卻產(chǎn)生了奇妙的效果——切換頁(yè)面之后,要等將近一分鐘才開(kāi)始渲染。我在它的隊(duì)列里放了幾個(gè) log,發(fā)現(xiàn)每個(gè)元素都被 queue 了 4 次,幾十個(gè)元素,難怪要一分鐘才開(kāi)始渲染下一頁(yè)的內(nèi)容,即使大部分 markdown 里面根本沒(méi)有數(shù)學(xué)。
這時(shí)候我開(kāi)始灰心了,這個(gè)問(wèn)題就沒(méi)有解決辦法了嗎?絕望之時(shí),我想到能不能直接 Typeset document,結(jié)果是可以的,而且十分快。所以渲染并不慢,可能是渲染的初始化過(guò)程比較慢。那么這時(shí)候方案就出來(lái)了,我們可以盡量減少渲染次數(shù),同時(shí)只渲染 document。只要這個(gè)渲染還在進(jìn)行,那么有再多的元素 queue 上來(lái),我們也只當(dāng)作 queue 了一次。
于是我就寫了這么個(gè) service:
@Injectable()
export class MathjaxService {
public isQueued = false;
public isRunning = false;
window: any;
constructor(@Inject(PLATFORM_ID) private platformId: Object) {
if (isPlatformBrowser(this.platformId)) {
this.window = window as any;
}
}
finishRunning() {
this.isRunning = false;
if (this.isQueued) {
this.queueChange();
}
}
queueChange() {
if (this.isRunning) {
this.isQueued = true;
} else {
this.isQueued = false;
this.isRunning = true;
if (isPlatformBrowser(this.platformId)) {
if (this.window.MathJax) {
this.window.MathJax.Hub.Config({
messageStyle: 'none',
tex2jax: {
// preview: 'none',
inlineMath: [['$', '$']],
processEscapes: true
}
});
this.window.MathJax.Hub.Queue(['log', console, 'start'], ['Typeset', this.window.MathJax.Hub, document], ['log', console, 'end'], ['finishRunning', this]);
}
} else {
this.finishRunning();
}
}
}
}
事實(shí)證明,它能圓滿完成任務(wù),它也就是現(xiàn)在運(yùn)行在 這個(gè)網(wǎng)站 上的代碼。
總結(jié)
以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。
相關(guān)文章
Angularjs Ng_repeat中實(shí)現(xiàn)復(fù)選框選中并顯示不同的樣式方法
今天小編就為大家分享一篇Angularjs Ng_repeat中實(shí)現(xiàn)復(fù)選框選中并顯示不同的樣式方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-09-09
AngularJs expression詳解及簡(jiǎn)單示例
本文主要介紹AngularJs expression,這里整理了詳細(xì)的資料,并附示例代碼,有興趣的小伙伴可以參考下2016-09-09
詳解angularjs中如何實(shí)現(xiàn)控制器和指令之間交互
本篇文章主要介紹了詳解angularjs中如何實(shí)現(xiàn)控制器和指令之間交互,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-05-05
angularJS實(shí)現(xiàn)不同視圖同步刷新詳解
今天小編就為大家分享一篇angularJS實(shí)現(xiàn)不同視圖同步刷新詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
AngularJS學(xué)習(xí)筆記之表單驗(yàn)證功能實(shí)例詳解
這篇文章主要介紹了AngularJS學(xué)習(xí)筆記之表單驗(yàn)證功能,結(jié)合實(shí)例形式分析了AngularJS針對(duì)表單的校驗(yàn)、監(jiān)控等相關(guān)操作技巧,需要的朋友可以參考下2017-07-07
angularJs中json數(shù)據(jù)轉(zhuǎn)換與本地存儲(chǔ)的實(shí)例
今天小編就為大家分享一篇angularJs中json數(shù)據(jù)轉(zhuǎn)換與本地存儲(chǔ)的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2018-10-10
AngularJS 使用ng-repeat報(bào)錯(cuò) [ngRepeat:dupes]
這篇文章主要介紹了AngularJS 使用ng-repeat報(bào)錯(cuò) [ngRepeat:dupes] 的相關(guān)資料,需要的朋友可以參考下2017-01-01

