我有这个模块,它将外部库与额外的逻辑组件化,而不直接将<script>标记添加到index.html中:
import 'http://external.com/path/file.js'
//import '../js/file.js'
@Component({
selector: 'my-app',
template: `
<script src="http://iknow.com/this/does/not/work/either/file.js"></script>
<div>Template</div>`
})
export class MyAppComponent {...}
我注意到ES6规范的导入是静态的,并且是在TypeScript编译期间解析的,而不是在运行时。
总之,让它变得可配置,这样file。js就会从CDN或本地文件夹加载?
如何告诉Angular 2动态加载脚本?
还有一种选择是利用scriptjs包来解决这个问题
允许您按需从任何URL加载脚本资源
例子
安装包:
npm i scriptjs
以及scriptjs的类型定义:
npm install --save @types/scriptjs
然后导入$script.get()方法:
import { get } from 'scriptjs';
最后加载脚本资源,在我们的例子中是谷歌Maps库:
export class AppComponent implements OnInit {
ngOnInit() {
get("https://maps.googleapis.com/maps/api/js?key=", () => {
//Google Maps library has been loaded...
});
}
}
Demo
我已经修改了@rahul kumars的答案,所以它使用可观察的代替:
import { Injectable } from "@angular/core";
import { Observable } from "rxjs/Observable";
import { Observer } from "rxjs/Observer";
@Injectable()
export class ScriptLoaderService {
private scripts: ScriptModel[] = [];
public load(script: ScriptModel): Observable<ScriptModel> {
return new Observable<ScriptModel>((observer: Observer<ScriptModel>) => {
var existingScript = this.scripts.find(s => s.name == script.name);
// Complete if already loaded
if (existingScript && existingScript.loaded) {
observer.next(existingScript);
observer.complete();
}
else {
// Add the script
this.scripts = [...this.scripts, script];
// Load the script
let scriptElement = document.createElement("script");
scriptElement.type = "text/javascript";
scriptElement.src = script.src;
scriptElement.onload = () => {
script.loaded = true;
observer.next(script);
observer.complete();
};
scriptElement.onerror = (error: any) => {
observer.error("Couldn't load script " + script.src);
};
document.getElementsByTagName('body')[0].appendChild(scriptElement);
}
});
}
}
export interface ScriptModel {
name: string,
src: string,
loaded: boolean
}
嗨,你可以使用Renderer2和elementRef只需几行代码:
constructor(private readonly elementRef: ElementRef,
private renderer: Renderer2) {
}
ngOnInit() {
const script = this.renderer.createElement('script');
script.src = 'http://iknow.com/this/does/not/work/either/file.js';
script.onload = () => {
console.log('script loaded');
initFile();
};
this.renderer.appendChild(this.elementRef.nativeElement, script);
}
onload函数可以用来在脚本加载后调用脚本函数,如果你必须在ngOnInit()中进行调用,这是非常有用的。
我发现这个解决方案更干净,首先在你的模块中导入HttpClientJsonpModule,然后做这样的事情
this.apiLoaded = this.httpClient.jsonp(environment.AnyApiUrl, 'callback')
.pipe(
map(() => true),
catchError(() => of(false)),
);
在模板中:
<app-component *ngIf="apiLoaded | async"></app-component>
这个解决方案在Angular谷歌Maps的官方文档中。