Angular 6 中的 MathJax?
MathJax in Angular 6?
不幸的是,关于这个库的信息很少。安装后我不完全清楚我需要将什么导入 app.module.ts 以及那里是否有要导入的东西?我在index.html中规定了以下代码:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\(','\)']]
}
});
</script>
<script type="text/javascript" async
src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?
config=TeX-MML-AM_CHTML'>
</script>
如果我没有简单的文本,而是 table 在某些列中出现带有公式的文本,我该如何应用 MathJax?也许你可以以某种方式将整个 table 转移到 MathJax.Hub.Queue?
两周前我也在看同样的问题,今天我终于设法解决了。我不是 angular 专家,所以它可能需要一些优化,但核心功能正在运行。
第一步
将 @types/mathjax
依赖项添加到您的 package.json
文件。
第二步
像这样将新添加的类型添加到 tsconfig.app.json
:
{
"compilerOptions": {
"types": ["mathjax"]
}
}
这将允许您使用 MathJax.Callback.Queue
等结构,并且您的 IDE 不会抱怨未知类型等。
第三步为您的数学内容创建包装器对象(可选)
我在使用 Mathml 时遇到了一些问题,所以我创建了数学包装器,如下所示:
export interface MathContent {
latex?: string;
mathml?: string;
}
第四步
现在我们需要定义模块,它将配置注入 MathJax 脚本标签。因为它将动态加载 async
我们需要确保在 MathJax 完全加载之前不会开始排版。最简单的方法是将 Observer<any>
存储到 window
对象中。 Observer
和渲染功能可以包装到服务中。
// see
declare global {
interface Window {
hubReady: Observer<boolean>;
}
}
@Injectable()
export class MathServiceImpl {
private readonly notifier: ReplaySubject<boolean>;
constructor() {
this.notifier = new ReplaySubject<boolean>();
window.hubReady = this.notifier; // as said, bind to window object
}
ready(): Observable<boolean> {
return this.notifier;
}
render(element: HTMLElement, math?: MathContent): void {
if (math) {
if (math.latex) {
element.innerText = math.latex;
} else {
element.innerHTML = math.mathml;
}
}
MathJax.Hub.Queue(['Typeset', MathJax.Hub, element]);
}
}
第五步
现在我们将创建指令,一旦加载 MathJax 就会触发渲染。该指令可能如下所示:
@Directive({
selector: '[appMath]'
})
export class MathDirective implements OnInit, OnChanges, OnDestroy {
private alive$ = new Subject<boolean>();
@Input()
private appMath: MathContent;
private readonly _el: HTMLElement;
constructor(private service: MathServiceImpl,
private el: ElementRef) {
this._el = el.nativeElement as HTMLElement;
}
ngOnInit(): void {
this.service
.ready()
.pipe(
take(1),
takeUntil(this.alive$)
).subscribe(res => {
this.service.render(this._el, this.appMath);
});
}
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
ngOnDestroy(): void {
this.alive$.next(false);
}
}
第六步(差不多了)
在第四步中我提到了 async
加载。根据 MathJax 上的文档,这是使用 document.createElement
完成的。 Angular 模块是这个逻辑的完美场所。要在我们的 MathService
上触发 .ready()
方法,我们将使用 MathJax.Hub.Register.StartupHook
并从 MathService
传递 observable 所以我们的模块将如下所示:
@NgModule({
declarations: [MathDirective],
exports: [MathDirective]
})
export class MathModule {
constructor(mathService: MathServiceImpl) {
// see https://docs.mathjax.org/en/latest/advanced/dynamic.html
const script = document.createElement('script') as HTMLScriptElement;
script.type = 'text/javascript';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML';
script.async = true;
document.getElementsByTagName('head')[0].appendChild(script);
const config = document.createElement('script') as HTMLScriptElement;
config.type = 'text/x-mathjax-config';
// register notifier to StartupHook and trigger .next() for all subscribers
config.text = `
MathJax.Hub.Config({
skipStartupTypeset: true,
tex2jax: { inlineMath: [["$", "$"]],displayMath:[["$$", "$$"]] }
});
MathJax.Hub.Register.StartupHook('End', () => {
window.hubReady.next();
window.hubReady.complete();
});
`;
document.getElementsByTagName('head')[0].appendChild(config);
}
// this is needed so service constructor which will bind
// notifier to window object before module constructor is called
public static forRoot(): ModuleWithProviders {
return {
ngModule: MathModule,
providers: [{provide: MathServiceImpl, useClass: MathServiceImpl}]
};
}
}
第七步:渲染数学
现在一切就绪,只需在要渲染数学的模块中导入 MathModule.forRoot()
即可。该组件将如下所示:
export class AppComponent {
mathLatex: MathContent = {
latex: 'When $a \ne 0$, there are two solutions to $\frac{5}{9}$'
};
mathMl: MathContent = {
mathml: `<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mover>
<munder>
<mo>∫</mo>
<mn>0</mn>
</munder>
<mi>∞</mi>
</mover>
<mtext> versus </mtext>
<munderover>
<mo>∫</mo>
<mn>0</mn>
<mi>∞</mi>
</munderover>
</mrow>
</math>`
};
}
和模板
<div [appMath]="mathLatex"></div>
<div [appMath]="mathMl"></div>
<!-- will render inline element math -->
<div [appMath]>
$E = mc^2$
</div>
哪个应该呈现给这个
第八步(奖金)
这是工作中的 stackblitz 示例 https://stackblitz.com/edit/mathjax-example 因此您可以检查您的实施进度
不幸的是,关于这个库的信息很少。安装后我不完全清楚我需要将什么导入 app.module.ts 以及那里是否有要导入的东西?我在index.html中规定了以下代码:
<script type="text/x-mathjax-config">
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\(','\)']]
}
});
</script>
<script type="text/javascript" async
src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/latest.js?
config=TeX-MML-AM_CHTML'>
</script>
如果我没有简单的文本,而是 table 在某些列中出现带有公式的文本,我该如何应用 MathJax?也许你可以以某种方式将整个 table 转移到 MathJax.Hub.Queue?
两周前我也在看同样的问题,今天我终于设法解决了。我不是 angular 专家,所以它可能需要一些优化,但核心功能正在运行。
第一步
将 @types/mathjax
依赖项添加到您的 package.json
文件。
第二步
像这样将新添加的类型添加到 tsconfig.app.json
:
{
"compilerOptions": {
"types": ["mathjax"]
}
}
这将允许您使用 MathJax.Callback.Queue
等结构,并且您的 IDE 不会抱怨未知类型等。
第三步为您的数学内容创建包装器对象(可选)
我在使用 Mathml 时遇到了一些问题,所以我创建了数学包装器,如下所示:
export interface MathContent {
latex?: string;
mathml?: string;
}
第四步
现在我们需要定义模块,它将配置注入 MathJax 脚本标签。因为它将动态加载 async
我们需要确保在 MathJax 完全加载之前不会开始排版。最简单的方法是将 Observer<any>
存储到 window
对象中。 Observer
和渲染功能可以包装到服务中。
// see
declare global {
interface Window {
hubReady: Observer<boolean>;
}
}
@Injectable()
export class MathServiceImpl {
private readonly notifier: ReplaySubject<boolean>;
constructor() {
this.notifier = new ReplaySubject<boolean>();
window.hubReady = this.notifier; // as said, bind to window object
}
ready(): Observable<boolean> {
return this.notifier;
}
render(element: HTMLElement, math?: MathContent): void {
if (math) {
if (math.latex) {
element.innerText = math.latex;
} else {
element.innerHTML = math.mathml;
}
}
MathJax.Hub.Queue(['Typeset', MathJax.Hub, element]);
}
}
第五步
现在我们将创建指令,一旦加载 MathJax 就会触发渲染。该指令可能如下所示:
@Directive({
selector: '[appMath]'
})
export class MathDirective implements OnInit, OnChanges, OnDestroy {
private alive$ = new Subject<boolean>();
@Input()
private appMath: MathContent;
private readonly _el: HTMLElement;
constructor(private service: MathServiceImpl,
private el: ElementRef) {
this._el = el.nativeElement as HTMLElement;
}
ngOnInit(): void {
this.service
.ready()
.pipe(
take(1),
takeUntil(this.alive$)
).subscribe(res => {
this.service.render(this._el, this.appMath);
});
}
ngOnChanges(changes: SimpleChanges): void {
console.log(changes);
}
ngOnDestroy(): void {
this.alive$.next(false);
}
}
第六步(差不多了)
在第四步中我提到了 async
加载。根据 MathJax 上的文档,这是使用 document.createElement
完成的。 Angular 模块是这个逻辑的完美场所。要在我们的 MathService
上触发 .ready()
方法,我们将使用 MathJax.Hub.Register.StartupHook
并从 MathService
传递 observable 所以我们的模块将如下所示:
@NgModule({
declarations: [MathDirective],
exports: [MathDirective]
})
export class MathModule {
constructor(mathService: MathServiceImpl) {
// see https://docs.mathjax.org/en/latest/advanced/dynamic.html
const script = document.createElement('script') as HTMLScriptElement;
script.type = 'text/javascript';
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/MathJax.js?config=TeX-MML-AM_CHTML';
script.async = true;
document.getElementsByTagName('head')[0].appendChild(script);
const config = document.createElement('script') as HTMLScriptElement;
config.type = 'text/x-mathjax-config';
// register notifier to StartupHook and trigger .next() for all subscribers
config.text = `
MathJax.Hub.Config({
skipStartupTypeset: true,
tex2jax: { inlineMath: [["$", "$"]],displayMath:[["$$", "$$"]] }
});
MathJax.Hub.Register.StartupHook('End', () => {
window.hubReady.next();
window.hubReady.complete();
});
`;
document.getElementsByTagName('head')[0].appendChild(config);
}
// this is needed so service constructor which will bind
// notifier to window object before module constructor is called
public static forRoot(): ModuleWithProviders {
return {
ngModule: MathModule,
providers: [{provide: MathServiceImpl, useClass: MathServiceImpl}]
};
}
}
第七步:渲染数学
现在一切就绪,只需在要渲染数学的模块中导入 MathModule.forRoot()
即可。该组件将如下所示:
export class AppComponent {
mathLatex: MathContent = {
latex: 'When $a \ne 0$, there are two solutions to $\frac{5}{9}$'
};
mathMl: MathContent = {
mathml: `<math xmlns="http://www.w3.org/1998/Math/MathML">
<mrow>
<mover>
<munder>
<mo>∫</mo>
<mn>0</mn>
</munder>
<mi>∞</mi>
</mover>
<mtext> versus </mtext>
<munderover>
<mo>∫</mo>
<mn>0</mn>
<mi>∞</mi>
</munderover>
</mrow>
</math>`
};
}
和模板
<div [appMath]="mathLatex"></div>
<div [appMath]="mathMl"></div>
<!-- will render inline element math -->
<div [appMath]>
$E = mc^2$
</div>
哪个应该呈现给这个
第八步(奖金)
这是工作中的 stackblitz 示例 https://stackblitz.com/edit/mathjax-example 因此您可以检查您的实施进度