从Angular组件动态加载外部javascript文件

psy*_*ych 39 typescript skyscanner angular

我正在使用Angular 4和CLI创建一个Angular应用程序.我正在尝试将SkyScanner搜索小部件添加到我的一个组件中.

Skyscanner Widget示例

部分实现需要添加新的外部脚本:

<script src="https://widgets.skyscanner.net/widget-server/js/loader.js" async></script>
Run Code Online (Sandbox Code Playgroud)

我不确定引用此文件的正确方法.如果我将脚本添加到我的index.html文件中,除非执行整页刷新,否则不会加载窗口小部件.我假设脚本在加载时尝试操作DOM,并且脚本运行时元素不存在.

仅在加载包含Skyscanner窗口小部件的组件时加载脚本的正确方法是什么?

San*_*per 64

尝试在组件加载上加载外部JavaScript,如下所示:

loadAPI: Promise<any>;

constructor() {        
    this.loadAPI = new Promise((resolve) => {
        this.loadScript();
        resolve(true);
    });
}

public loadScript() {        
    var isFound = false;
    var scripts = document.getElementsByTagName("script")
    for (var i = 0; i < scripts.length; ++i) {
        if (scripts[i].getAttribute('src') != null && scripts[i].getAttribute('src').includes("loader")) {
            isFound = true;
        }
    }

    if (!isFound) {
        var dynamicScripts = ["https://widgets.skyscanner.net/widget-server/js/loader.js"];

        for (var i = 0; i < dynamicScripts.length; i++) {
            let node = document.createElement('script');
            node.src = dynamicScripts [i];
            node.type = 'text/javascript';
            node.async = false;
            node.charset = 'utf-8';
            document.getElementsByTagName('head')[0].appendChild(node);
        }

    }
}
Run Code Online (Sandbox Code Playgroud)

  • 但是此文件加载会延迟,因此我的功能在没有这些知识的情况下就会呈现。后来却没有用 如何解决这个问题。 (2认同)
  • 我尝试过这个..它仅适用于重新加载...例如。如果您要从一个组件导航到另一个组件。第一次会冻结,重新加载页面后将与动态脚本一起正确显示 (2认同)
  • @GoutamBSeervi 您是否找到了延迟加载的任何解决方案。我也面临同样的问题.. (2认同)

Wil*_*vo 22

我有同样的问题,但在我的情况下,我在html文件的末尾导入10个库,这些库有很多方法,听众,事件等等,在我的情况下我不需要专门调用一个方法.

关于我拥有的例子:

<!-- app.component.html -->

<div> 
 ...
</div>

<script src="http://www.some-library.com/library.js">
<script src="../assets/js/my-library.js"> <!-- a route in my angular project -->
Run Code Online (Sandbox Code Playgroud)

如上所述,它没有用.然后,我发现了帮助我的东西:Milad的反应

  1. 删除app.component.html中的脚本调用.您必须在app.component.ts文件中链接这些脚本.

  2. 在ngOnInit()中,使用方法来附加库,例如:

``

<!-- app.component.ts -->

export class AppComponent implements OnInit {
   title = 'app';
   ngOnInit() {
     this.loadScript('http://www.some-library.com/library.js');
     this.loadScript('../assets/js/my-library.js');
   }
  }

  public loadScript(url: string) {
    const body = <HTMLDivElement> document.body;
    const script = document.createElement('script');
    script.innerHTML = '';
    script.src = url;
    script.async = false;
    script.defer = true;
    body.appendChild(script);
  }
}
Run Code Online (Sandbox Code Playgroud)

它对我有用.我使用Angular 6,希望它有所帮助.


Edu*_*gas 7

我已完成此代码段

 addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.elementRef.nativeElement.appendChild(script);
    return script;
  }
Run Code Online (Sandbox Code Playgroud)

然后像这样称呼它

this.addJsToElement('https://widgets.skyscanner.net/widget-server/js/loader.js').onload = () => {
        console.log('SkyScanner Tag loaded');
}
Run Code Online (Sandbox Code Playgroud)

编辑:使用新的渲染器Api,它可以像这样写

constructor(private renderer: Renderer2){}

 addJsToElement(src: string): HTMLScriptElement {
    const script = document.createElement('script');
    script.type = 'text/javascript';
    script.src = src;
    this.renderer.appendChild(document.body, script);
    return script;
  }
Run Code Online (Sandbox Code Playgroud)

StackBlitz


Ham*_*our 6

添加loader.js到您的资产文件夹然后在您的angular-cli.json

"scripts": ["./src/assets/loader.js",]
Run Code Online (Sandbox Code Playgroud)

然后将此添加到您的 typings.d.ts

 declare var skyscanner:any;
Run Code Online (Sandbox Code Playgroud)

你将能够使用它

  skyscanner.load("snippets","2");
Run Code Online (Sandbox Code Playgroud)


Ani*_*wal 5

您可以创建自己的指令来加载脚本,如下所示

import { Directive, OnInit, Input } from '@angular/core';

@Directive({
    selector: '[appLoadScript]'
})
export class LoadScriptDirective implements OnInit{

    @Input('script') param:  any;

    ngOnInit() {
        let node = document.createElement('script');
        node.src = this.param;
        node.type = 'text/javascript';
        node.async = false;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }

}
Run Code Online (Sandbox Code Playgroud)

您可以在组件模板中的任何位置使用它,如下所示

<i appLoadScript  [script]="'script_file_path'"></i>
Run Code Online (Sandbox Code Playgroud)

例如,要在组件中动态加载JQuery,请在组件模板中插入以下代码

<i appLoadScript  [script]="'/assets/baker/js/jquery.min.js'"></i>
Run Code Online (Sandbox Code Playgroud)