Angular 6中的MathJax吗?

M*_*ark 4 mathjax angular angular6

不幸的是,关于这个库的信息很少。安装后我还不太清楚我需要将哪些内容导入到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>
Run Code Online (Sandbox Code Playgroud)

如果我没有简单的文本,但是在某些列中出现带有公式的文本的表,该如何应用MathJax?也许您可以以某种方式将整个表转移到MathJax.Hub.Queue?

emp*_*tak 6

我在两个星期前就一直在研究相同的问题,而今天我终于设法使它起作用。我不是专家,因此可能需要一些优化,但是核心功能正在发挥作用。

步骤1

@types/mathjaxpackage.json文件添加依赖项。

第二步

tsconfig.app.json像这样添加新添加的类型:

{
  "compilerOptions": {
    "types": ["mathjax"]
  }
}
Run Code Online (Sandbox Code Playgroud)

这将允许您使用诸如之类的构造,MathJax.Callback.Queue并且您的IDE不会抱怨未知类型等。

第三步为您的数学内容创建包装对象(可选)

我在Mathml中遇到了一些问题,因此我为数学创建了包装器,如下所示:

{
  "compilerOptions": {
    "types": ["mathjax"]
  }
}
Run Code Online (Sandbox Code Playgroud)

第四步

现在我们需要定义一个模块,该模块将通过配置注入MathJax脚本标签。因为它将动态加载,所以async我们需要确保在MathJax完全加载之前不会开始排版。最简单的方法是存储Observer<any>window对象中。Observer渲染功能可以包装到服务中。

export interface MathContent {
  latex?: string;
  mathml?: string;
}
Run Code Online (Sandbox Code Playgroud)

第五步

现在我们将创建伪指令,一旦加载MathJax,该伪指令将触发渲染。该指令可能如下所示:

// see https://stackoverflow.com/a/12709880/1203690
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]);
  }
}
Run Code Online (Sandbox Code Playgroud)

第六步(几乎在那里)

在第四步中,我提到了async加载。根据MathJax上的文档,这是使用完成的document.createElement。Angular Module是此逻辑的理想之地。要.ready()在我们上触发方法,MathService我们将使用MathJax.Hub.Register.StartupHook并从它传递observable,MathService因此我们的模块将如下所示:

@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);
  }
}
Run Code Online (Sandbox Code Playgroud)

第七步:渲染数学

现在一切就绪,只需将其导入MathModule.forRoot()要渲染数学的模块即可。该组件将如下所示:


@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}]
    };
  }
}
Run Code Online (Sandbox Code Playgroud)

和模板

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>`
  };
}
Run Code Online (Sandbox Code Playgroud)

哪个应该对此

在此处输入图片说明

第八步(奖金)

这是工作中的stackblitz示例https://stackblitz.com/edit/mathjax-example,因此您可以根据实现检查进度