2016-06-09 84 views
9

我想從網站加載第三方腳本,而不是製作它的本地副本,並能夠使用第三方腳本的全局變量和函數後腳本加載。如何從Web動態加載第三方腳本到Angular2組件

更新

  • 這裏是我試圖在普通的JavaScript實現,其中關於簽證結帳按鈕點擊一個示例打開簽證檢出對話框: Plunker JS link
  • 這裏的Angular2版本我需要幫助的地方: Plunker Angular2 link

問題:下面的組件不從w加載腳本EB

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!!' 
 
    } 
 
}

回答

2

有跡象表明,這是可以實現的兩種方式。

  1. 引用您要添加的第三方腳本的類型定義文件。類型定義文件通常以.d.ts結尾,基本上是腳本功能的接口。如果沒有預先定義的類型定義文件,您可以使用您需要的功能創建一個自己的自己。 (我更喜歡這種方法,因爲有些IDE會給你方法簽名作爲intellisense的一部分)
  2. 在TypeScript類的頂部創建一個變量,該變量表示您正在使用的類型爲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是否會爲您創建參考。)

聲明:

declare var automapper: any; 

@Component({ 
    selector: "my-app", 
}) 
export class AppComponent { 
    constructor() { 
     automapper.map("JSON", "myType", jsonObj); 
    } 
} 

第三方JS文件,可以使用標準的<script>標籤的進口被加載。以上方法適用於TS編譯器,以便它不會因未知的變量異常而失敗。

+0

由於包括該代碼爲快速反應。我是Angular的新手,我不太瞭解你的回答。你能用Plunker的例子看看我更新的問題嗎?真的很感謝幫助! – Rishi

+0

我看了一下你的Plunker,但現在這個網站已經關閉了。我看到的第一個問題是,您不應該在組件的模板中包含'script'標記,因爲Angular將它們去掉。第三部分腳本應該加載到'index.html'中。一旦Plunker回來,我會再看一次。 –

+0

雖然我想看看它是如何工作的,包括在index.html的劇本,我寧願延遲加載腳本時,我的分量一起。在這種特殊情況下,我還需要訪問在my-component中從web加載的腳本的全局變量。 – Rishi

9

您可以使用此技術在您的Angular 2/4項目中按需動態加載JS腳本和庫。

創建ScriptStorescript.store中。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' } 
]; 

創建script.service.ts提供ScriptService作爲可處理腳本文件加載的注入服務。無論你需要它,並加載腳本這樣

import {Injectable} from "@angular/core"; 
import {ScriptStore} from "./script.store"; 

declare var document: any; 

@Injectable() 
export class Script { 

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

constructor(
    private scriptService: ScriptService 
) { } 

ngOnInit() { 
    this.scriptService.load('filepicker', 'rangeSlider').then(data => { 
     console.log('script loaded ', data); 
    }).catch(error => console.log(error)); 
} 
2

我已經修改Rahul Kumar's answer,以便它使用觀測量,而不是:

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 
} 
+0

歡呼聲......它可以加載......但我將如何執行它?並模仿異步功能? –