下载Angular 2组件并运行脚本

时间:2016-12-06 09:37:15

标签: javascript angular mathjax

我正在尝试使用MathJax在我的Angular 2应用中显示公式。我的应用程序中只有一小部分确实需要此功能,因此我不希望所有用户都必须下载所需的3-400kb。

我最初的想法是在我的组件中import "mathjax",因此只有在创建组件时才会加载库。但是,我了解到from my earlier question MathJax并不能很好地与其他人合作,因为它使用自己的自定义模块加载器。

我当前的设置会从script加载index.html,但这意味着当只有一小部分用户需要此组件时,所有人将下载

<script src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=AM_SVG"></script>

Angular 2中是否有一种干净的方法让我的组件在ngOnInit()挂钩中下载脚本并在DOM中执行回调?诸如(伪代码)之类的东西:

ngOnInit(){
    //download script, add to DOM      
    fetch('https://...MathJax.js').then(addToDom).then(this.onMathJaxLoaded);
}
onMathJaxLoaded(){
  // Run math renderer
  MathJax.Hub.Queue("Typeset",...);
}

2 个答案:

答案 0 :(得分:6)

我没试过,但我认为这可能是可能的:

ngOnInit(){
    //download script, add to DOM      
    var script = document.createElement('script');
    document.body.appendChild(script)
    script.onload = this.onMathJaxLoaded.bind(this);
    script.src = 'https://...MathJax.js';
}
onMathJaxLoaded(){
  // Run math renderer
  MathJax.Hub.Queue("Typeset",...);
}

这是一个小提琴,其中包含一个如何在纯JavaScript中工作的示例; https://jsfiddle.net/5qu5h7bc/

答案 1 :(得分:2)

在@ TryingToImprove的解决方案的基础上,我决定使用ScriptLoaderService函数向我的应用添加load(),该函数提取远程脚本并通知调用者(使用RxJS Observable })当它完成。

以下是如何使用它:

this.scriptLoaderService.load('https://...js').subscribe(
    ()=>console.log('script has loaded');
);

这是服务:

/**
 * A directory of scripts that have been or are being loaded
 */
private scripts = new Map<string,Observable<boolean>|boolean>();

/**
 * Downloads script; returns Observable that emits TRUE once "load" event fires
 */
public load(src:string):Observable<boolean>{        
    if(this.scripts.has(src)){
        // If script has already been fully loaded.
        if(this.scripts.get(src)===true) return Observable.of(true);

        // Else if download is already underway but load event hasn't fired yet
        else return this.scripts.get(src);
    }

    //Add a script tag to the DOM
    let script = document.createElement('script');
    document.body.appendChild(script);

    // upon subscription, listen for the load event. Once it arrives, emit TRUE
    let obs:Observable<boolean> = Observable.fromEvent(script,'load')
        // Map should hold TRUE once script is loaded
        .do(()=> this.scripts.set(src,true))
        .take(1).map(e=>true);

    // set the src attribute (will cause browser to download)
    script.src = src;

    //add observable to the scripts Map
    this.scripts.set(src,obs);

    return obs;
}

Firefox 51

上进行测试