Angular中使用MathJax遇到的一些问题
- 作者: 中单德玛咿呀
- 来源: 51数据库
- 2021-08-11
前言
话说我本来是倾向于 katex 的,因为我感觉他很快,而且 mathjax 似乎很难配。但是大家表示对缺少功能的 katex 并无好感,给我提供了一些钻研 mathjax 的动力。
mathjax简介
mathjax是一款运行在浏览器中的开源数学符号渲染引擎,使用mathjax可以方便的在浏览器中显示数学公式,不需要使用图片。目前,mathjax可以解析latex、mathml和asciimathml的标记语言。mathjax项目于2009年开始,发起人有american mathematical society, design science等,还有众多的支持者,个人感觉mathjax会成为今后数学符号渲染引擎中的主流,也许现在已经是了。
个人其实也不算钻研,因为实际上 mathjax 很简单,调用 mathjax.hub.queue(['typeset', mathjax.hub, this.element.nativeelement]); 就可以渲染一个元素(这个 this.element.nativeelement 是从 angular 中调用它 dom 的语法),这个 .queue 实际上是 mathjax 自己实现的回调格式,语法非常清奇,参数个数不定,每个都是数组,代表一个回调,顺序执行。比如这个 ['typeset', mathjax.hub, this.element.nativeelement] ,第一个元素是方法名,第二个元素是 this ,之后的元素都是参数……
我们可以看到这个就相当于执行 mathjax.hub.typeset(this.element.nativeelement) ,那为啥不执行这个?因为这方法是同步的,会导致页面十分卡。于是 mathjax 就自己封装了一个异步队列(它的 api 可能几百年没改了)
我们说回 angular。因为要用 markdown,我的思路是用 marked 封装一个 directive。那么我们就应该在 marked 渲染完成之后用 mathjax 去 typeset 这个组件。但真的这样做了,却产生了奇妙的效果——切换页面之后,要等将近一分钟才开始渲染。我在它的队列里放了几个 log,发现每个元素都被 queue 了 4 次,几十个元素,难怪要一分钟才开始渲染下一页的内容,即使大部分 markdown 里面根本没有数学。
这时候我开始灰心了,这个问题就没有解决办法了吗?绝望之时,我想到能不能直接 typeset document,结果是可以的,而且十分快。所以渲染并不慢,可能是渲染的初始化过程比较慢。那么这时候方案就出来了,我们可以尽量减少渲染次数,同时只渲染 document。只要这个渲染还在进行,那么有再多的元素 queue 上来,我们也只当作 queue 了一次。
于是我就写了这么个 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();
}
}
}
}
事实证明,它能圆满完成任务,它也就是现在运行在 上的代码。
总结
以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对的支持。
