我正在尝试从网上加载第三方脚本,而不是制作它的本地副本,并且能够在脚本加载后使用第三方脚本的全局变量和函数。
更新:
问题:下面的组件未从Web加载脚本
import {Component} from '@angular/core'
@Component({
selector: 'custom',
providers: [],
template: `
<div>
<h2>{{name}}</h2>
<img class="v-button" role="button" alt="Visa Checkout" src="https://sandbox.secure.checkout.visa.com/wallet-services-web/xo/button.png">
<script src="https://sandbox-assets.secure.checkout.visa.com/checkout-widget/resources/js/integration/v1/sdk.js">
</script>
</div>
`
})
export class CustomComponent {
constructor() {
this.name = 'Custom Component works!!'
}
}
&#13;
答案 0 :(得分:11)
您可以使用此技术在Angular 2/4项目中按需动态加载JS脚本和库。
在 script.store.ts 中创建Identity
,其中包含本地或远程服务器上的路径以及名称将用于动态加载脚本:
ScriptStore
创建 script.service.ts 以提供interface Scripts {
name: string;
src: string;
}
export const ScriptStore: Scripts[] = [
{name: 'filepicker', src: 'https://api.filestackapi.com/filestack.js'},
{name: 'rangeSlider', src: '../../../assets/js/ion.rangeSlider.min.js'}
];
作为可注入服务,该服务将处理脚本文件的加载。包括此代码:
ScriptService
在您需要的地方注入import {Injectable} from "@angular/core";
import {ScriptStore} from "./script.store";
declare var document: any;
@Injectable()
export class ScriptService {
private scripts: any = {};
constructor() {
ScriptStore.forEach((script: any) => {
this.scripts[script.name] = {
loaded: false,
src: script.src
};
});
}
load(...scripts: string[]) {
var promises: any[] = [];
scripts.forEach((script) => promises.push(this.loadScript(script)));
return Promise.all(promises);
}
loadScript(name: string) {
return new Promise((resolve, reject) => {
//resolve if already loaded
if (this.scripts[name].loaded) {
resolve({script: name, loaded: true, status: 'Already Loaded'});
}
else {
//load script
let script = document.createElement('script');
script.type = 'text/javascript';
script.src = this.scripts[name].src;
if (script.readyState) { //IE
script.onreadystatechange = () => {
if (script.readyState === "loaded" || script.readyState === "complete") {
script.onreadystatechange = null;
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
}
};
} else { //Others
script.onload = () => {
this.scripts[name].loaded = true;
resolve({script: name, loaded: true, status: 'Loaded'});
};
}
script.onerror = (error: any) => resolve({script: name, loaded: false, status: 'Loaded'});
document.getElementsByTagName('head')[0].appendChild(script);
}
});
}
}
并加载如下脚本:
ScriptService
答案 1 :(得分:2)
有两种方法可以实现。
.d.ts
结尾,基本上是脚本功能的接口。如果没有预定义的类型定义文件,您可以使用所需的功能创建自己的文件。 (我更喜欢这种方法,因为有些IDE会给你方法签名作为intellisense的一部分)any
; 使用AutoMapperTS的示例:
类型定义:
/// <reference path="../node_modules/automapper-ts/dist/automapper.d.ts" />
@Component({
selector: "my-app",
})
export class AppComponent {
constructor() {
automapper.map("JSON", "myType", jsonObj);
}
}
(此示例中的引用可能因编辑器而异。此示例使用的是Visual Studio。尝试将要引用的文件拖到编辑器窗口中,以查看IDE是否将为您创建引用。)< / p>
<强>声明:强>
declare var automapper: any;
@Component({
selector: "my-app",
})
export class AppComponent {
constructor() {
automapper.map("JSON", "myType", jsonObj);
}
}
可以使用标准<script>
标记导入加载第三方JS文件。上述方法适用于TS编译器,因此它不会因未知变量异常而失败。
答案 2 :(得分:2)
我修改了Rahul Kumar's answer,以便它使用Observables代替:
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
}