วิธีการโหลดสคริปต์ภายนอกแบบไดนามิกในเชิงมุม?


150

ฉันมีโมดูลนี้ซึ่งประกอบห้องสมุดภายนอกพร้อมกับตรรกะเพิ่มเติมโดยไม่ต้องเพิ่ม<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 {...}

ฉันสังเกตเห็นว่าimportข้อมูลจำเพาะโดย ES6 นั้นเป็นแบบสแตติกและได้รับการแก้ไขระหว่างการถ่ายทำ TypeScript แทนที่จะใช้งานจริง

ยังไงก็ตามเพื่อให้สามารถกำหนดค่าได้ดังนั้น file.js จะโหลดจาก CDN หรือโฟลเดอร์ในเครื่องใช่ไหม จะบอก Angular 2 ให้โหลดสคริปต์ได้อย่างไร


คำตอบ:


61

หากคุณใช้ system.js คุณสามารถใช้งานได้System.import()ที่ runtime:

export class MyAppComponent {
  constructor(){
    System.import('path/to/your/module').then(refToLoadedModule => {
      refToLoadedModule.someFunction();
    }
  );
}

หากคุณใช้ webpack คุณสามารถใช้ประโยชน์จากการสนับสนุนการแยกรหัสที่มีประสิทธิภาพด้วยrequire.ensure:

export class MyAppComponent {
  constructor() {
     require.ensure(['path/to/your/module'], require => {
        let yourModule = require('path/to/your/module');
        yourModule.someFunction();
     }); 
  }
}

1
ดูเหมือนว่าฉันต้องใช้ตัวโหลดโมดูลโดยเฉพาะในส่วนประกอบ นั่นเป็นเรื่องดีเพราะSystemอนาคตของตัวโหลดฉันคิดว่า
CallMeLaNN

6
TypeScript Plugin for Sublime Textไม่พอใจกับSystemรหัส TypeScript: Cannot find name 'System'แต่ไม่มีข้อผิดพลาดระหว่างการทำ transpiling และการทำงาน ทั้งAngular2และSystemไฟล์สคริปต์ถูกเพิ่มเข้าไปindex.htmlแล้ว ต่อไปเพื่อและทำให้มีความสุขปลั๊กอิน? importSystem
CallMeLaNN

1
แต่ถ้าคุณไม่ได้ใช้ system.js!
Murhaf Sousli

2
@drewmoore ฉันจำไม่ได้ว่าทำไมฉันถึงพูดแบบนั้นrequire()/ importควรจะทำงานได้ดีเหมือนคำตอบของคุณตอนนี้ +1
Murhaf Sousli

9
จากสิ่งที่ฉันสามารถบอกได้ว่าตัวเลือกเหล่านี้ใช้ไม่ได้กับสคริปต์บนอินเทอร์เน็ตเพียงแค่ไฟล์ในเครื่องเท่านั้น ดูเหมือนว่าจะไม่ตอบคำถามเดิมตามที่ถาม
WillyC

139

คุณสามารถใช้เทคนิคต่อไปนี้เพื่อโหลดสคริปต์ JS และไลบรารีตามคำขอในโครงการแองกูลาร์ของคุณ

script.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เป็นบริการฉีดที่จะจัดการกับการโหลดสคริปต์คัดลอกscript.service.tsตามที่เป็นอยู่

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ทุกที่ที่คุณต้องการและโหลด js libs เช่นนี้

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

7
มันใช้งานได้ดี ลดขนาดการโหลดเริ่มต้นเกิน 1MB - ฉันมีห้องสมุดมากมาย!
Our_Benefactors ของเรา

2
ดูเหมือนว่าฉันจะพูดเร็วเกินไป วิธีนี้ไม่ทำงานใน iOS Safari
Our_Benefactors

หลังจากโหลดสคริปต์ตรวจสอบว่ามันผนวกกับหัวของคุณ
Rahul Kumar

บางทีฉันไม่ได้ฉีดอย่างถูกต้อง แต่ฉันได้รับthis.script.load is not a function
Towelie

ขอบคุณ ใช้งานได้ แต่ฉันได้รับสคริปต์ของฉัน (ภาพเคลื่อนไหวพื้นหลัง) โหลดในทุกองค์ประกอบอื่น ๆ ฉันต้องการให้โหลดเฉพาะในองค์ประกอบแรกของฉัน (เป็นหน้าเข้าสู่ระบบ) ฉันจะทำอย่างไรเพื่อให้บรรลุเป้าหมายนั้น ขอบคุณ
Joel Azevedo

47

สิ่งนี้อาจใช้ได้ รหัสนี้ผนวก<script>แท็กเข้ากับปุ่มheadของไฟล์ html ที่คลิกแบบไดนามิก

const url = 'http://iknow.com/this/does/not/work/either/file.js';

export class MyAppComponent {
    loadAPI: Promise<any>;

    public buttonClicked() {
        this.loadAPI = new Promise((resolve) => {
            console.log('resolving promise...');
            this.loadScript();
        });
    }

    public loadScript() {
        console.log('preparing to load...')
        let node = document.createElement('script');
        node.src = url;
        node.type = 'text/javascript';
        node.async = true;
        node.charset = 'utf-8';
        document.getElementsByTagName('head')[0].appendChild(node);
    }
}

1
ชาย Thanx ทำงานให้ฉัน ขณะนี้คุณสามารถโหลดได้ที่การโหลดหน้าเว็บโดยใช้วิธี ngonit ดังนั้นจึงไม่จำเป็นต้องคลิกปุ่ม
Niraj

ฉันใช้วิธีเดียวกัน .. แต่ไม่ได้ผลสำหรับฉัน คุณช่วยฉันออกไปด้วยได้ไหม? this.loadJs ("เส้นทาง javascriptfile"); loadjs สาธารณะ (ไฟล์) {let node = document.createElement ('สคริปต์'); node.src = ไฟล์; node.type = 'text / javascript'; node.async = true; node.charset = 'utf-8'; document.getElementsByTagName ( 'หัว') [0] .appendChild (โหนด); }
Mitesh Shah

คุณพยายามที่จะคลิกหรือโหลดหน้า? คุณสามารถบอกเราเพิ่มเติมเกี่ยวกับผลลัพธ์หรือข้อผิดพลาดได้หรือไม่?
ng-darren

สวัสดีฉันพยายามใช้งานและใช้งานได้ดี แต่new Promiseไม่ได้รับการแก้ไข คุณบอกฉันได้ไหมว่าPromiseฉันต้องนำเข้าอะไร
user3145373 ツ

สวัสดีฉันไม่ได้นำเข้าอะไรเป็นพิเศษเมื่อฉันใช้สัญญา
ng-darren

23

ฉันได้แก้ไข @rahul kumars แล้วดังนั้นจึงใช้ 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
}

1
คุณลืมตั้งค่าการasync true
Will Huang

ฉันมีคำถามเมื่อเราต่อท้ายสคริปต์และนำทางระหว่างเส้นทางสมมติว่าฉันโหลดสคริปต์ที่บ้านและเรียกดูเกี่ยวกับและกลับไปที่บ้านมีวิธีที่จะรวมสคริปต์ปัจจุบันหรือไม่ หมายถึงฉันต้องการลบอันที่เคยโหลดก่อนหน้านี้และโหลดอีกครั้ง ขอบคุณมาก
d123546

@ d123546 ใช่ถ้าคุณต้องการให้เป็นไปได้ แต่คุณต้องเขียนตรรกะบางอย่างที่ลบแท็กสคริปต์ ดูได้ที่นี่: stackoverflow.com/questions/14708189/…
Joel

ขอบคุณ Joel แต่มีวิธีลบฟังก์ชั่นที่เริ่มต้นโดยสคริปต์หรือไม่? ขณะนี้ฉันกำลังประสบปัญหาในโครงการ angular4 ของฉันเพราะฉันกำลังโหลดสคริปต์ที่เริ่มต้นตัวเลื่อน jquery ดังนั้นเมื่อเส้นทางแรกโหลดมันแสดงอย่างถูกต้อง แต่เมื่อฉันนำทางไปยังเส้นทางอื่นและกลับสู่เส้นทางของฉันสคริปต์ถูกโหลดสองครั้งและตัวเลื่อน ไม่ได้โหลดอีกต่อไป :( คุณช่วยแนะนำฉันเกี่ยวกับเรื่องนี้ได้
ไหม

1
private scripts: {ScriptModel}[] = [];เกิดข้อผิดพลาดในแนวเดียวกันคือ มันควรจะเป็นprivate scripts: ScriptModel[] = [];
Chris Haines

20

อีกทางเลือกหนึ่งคือการใช้ประโยชน์จากscriptjsแพ็คเกจสำหรับสิ่งที่

ช่วยให้คุณโหลดทรัพยากรสคริปต์ตามความต้องการจาก URL ใด ๆ

ตัวอย่าง

ติดตั้งแพ็คเกจ:

npm i scriptjs

และคำจำกัดความประเภทสำหรับscriptjs :

npm install --save @types/scriptjs

จากนั้นนำเข้า$script.get()วิธีการ:

import { get } from 'scriptjs';

และสุดท้ายโหลดทรัพยากรสคริปต์ในกรณีห้องสมุด Google Maps ของเรา:

export class AppComponent implements OnInit {
  ngOnInit() {
    get("https://maps.googleapis.com/maps/api/js?key=", () => {
        //Google Maps library has been loaded...
    });
  }
}

การสาธิต


ขอบคุณที่แบ่งปัน แต่จะเพิ่มสถานที่ให้บริการด้วย url เช่น async ได้อย่างไร? คุณช่วยแนะนำวิธีการโหลดสคริปต์นี้โดยใช้ห้องสมุดด้านบนได้ไหม? <script type = 'text / javascript' src = ' bing.com/api/maps/mapcontrol?branch=release ' การซิงค์แบบ async> </script>
Pushkar Rathod

เนื่องจากหัวเรื่องเดียวกันฉันกำลังตอบเพียงที่นี่เท่านั้น
Pushkar Rathod

เยี่ยมมาก แต่แทนที่จะติดตั้ง npm --save @ types / scriptjs ก็ควรจะติดตั้ง npm --save-dev @ types / scriptjs (หรือเพียงแค่ npm i -D @ ประเภท / scriptjs)
Youness Houdass

18

คุณสามารถโหลดหลายสคริปต์แบบไดนามิกเช่นนี้ในcomponent.tsไฟล์ของคุณ:

 loadScripts() {
    const dynamicScripts = [
     'https://platform.twitter.com/widgets.js',
     '../../../assets/js/dummyjs.min.js'
    ];
    for (let i = 0; i < dynamicScripts.length; i++) {
      const 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);
    }
  }

และเรียกวิธีนี้ภายในนวกรรมิก

constructor() {
    this.loadScripts();
}

หมายเหตุ: เพื่อให้สามารถโหลดสคริปต์เพิ่มเติมแบบไดนามิกให้เพิ่มไปยังdynamicScriptsอาร์เรย์


3
ผมต้องบอกว่ารูปลักษณ์ที่เรียบง่าย แต่ทำงานได้ดีมากง่ายต่อการใช้ :-)
ปิแอร์

3
ปัญหาของการฉีดสคริปต์ประเภทนี้คือเนื่องจาก Angular เป็นสปาสคริปต์นี้จะยังคงอยู่ในแคชของเบราว์เซอร์โดยทั่วไปแม้ว่าคุณจะลบแท็กสคริปต์ออกจาก DOM
j4rey

1
คำตอบที่ยอดเยี่ยม! บันทึกวันของฉันใช้งานได้กับ Angular 6 และ 7 ทดสอบแล้ว!
Nadeeshan Herath

ในการส่งข้อมูลไปยัง js ภายนอกและรับข้อมูลจาก js ภายนอกให้เรียกใช้ฟังก์ชันนี้ที่ app.component.ts และใช้ประกาศ var d3Sankey: ใด ๆ ที่องค์ประกอบของโมดูลระดับคุณลักษณะใด ๆ มันใช้งานได้ดี
gnganpath

5

ฉันได้ทำโค้ดขนาดสั้นนี้กับ 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;
  }

แล้วเรียกมันว่าสิ่งนี้

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

StackBlitz


4

ฉันมีวิธีที่ดีในการโหลดสคริปต์แบบไดนามิก! ตอนนี้ฉันใช้ ng6, echarts4 (> 700Kb), ngx-echarts3 ในโครงการของฉัน เมื่อฉันใช้เอกสารเหล่านี้โดย doc ของ ngx-echarts ฉันต้องการนำเข้า echarts ใน angular.json: "สคริปต์": ["./ node_modules / echarts / dist / echarts.min.js"] ดังนั้นในโมดูลการเข้าสู่ระบบหน้าในขณะที่โหลดสคริปต์ .js นี่คือไฟล์ขนาดใหญ่! ฉันไม่ต้องการมัน

ดังนั้นฉันคิดว่าโหลดเชิงมุมแต่ละโมดูลเป็นไฟล์ฉันสามารถแทรกตัวแก้ปัญหาเราเตอร์เพื่อโหลด js ล่วงหน้าแล้วเริ่มโหลดโมดูล!

// PreloadScriptResolver.service.js

/**动态加载js的服务 */
@Injectable({
  providedIn: 'root'
})
export class PreloadScriptResolver implements Resolve<IPreloadScriptResult[]> {
  // Here import all dynamically js file
  private scripts: any = {
    echarts: { loaded: false, src: "assets/lib/echarts.min.js" }
  };
  constructor() { }
  load(...scripts: string[]) {
    const promises = scripts.map(script => this.loadScript(script));
    return Promise.all(promises);
  }
  loadScript(name: string): Promise<IPreloadScriptResult> {
    return new Promise((resolve, reject) => {
      if (this.scripts[name].loaded) {
        resolve({ script: name, loaded: true, status: 'Already Loaded' });
      } else {
        const script = document.createElement('script');
        script.type = 'text/javascript';
        script.src = this.scripts[name].src;
        script.onload = () => {
          this.scripts[name].loaded = true;
          resolve({ script: name, loaded: true, status: 'Loaded' });
        };
        script.onerror = (error: any) => reject({ script: name, loaded: false, status: 'Loaded Error:' + error.toString() });
        document.head.appendChild(script);
      }
    });
  }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Promise<IPreloadScriptResult[]> {
   return this.load(...route.routeConfig.data.preloadScripts);
  }
}

จากนั้นใน submodule-routing.module.ts, นำเข้า PreloadScriptResolver นี้:

const routes: Routes = [
  {
    path: "",
    component: DashboardComponent,
    canActivate: [AuthGuardService],
    canActivateChild: [AuthGuardService],
    resolve: {
      preloadScripts: PreloadScriptResolver
    },
    data: {
      preloadScripts: ["echarts"]  // important!
    },
    children: [.....]
}

รหัสนี้ทำงานได้ดีและสัญญาว่า: หลังจากโหลดไฟล์ js แล้วโมดูลจะเริ่มโหลด! Resolver นี้สามารถใช้ในเราเตอร์หลายตัว


คุณกรุณาแบ่งปันรหัสของ IPreloadScriptResult
Mehul Bhalala

3

สารละลายสากลเชิงมุม ฉันต้องรอให้องค์ประกอบเฉพาะอยู่บนหน้าก่อนที่จะโหลดสคริปต์เพื่อเล่นวิดีโอ

import {Inject, Injectable, PLATFORM_ID} from '@angular/core';
import {isPlatformBrowser} from "@angular/common";

@Injectable({
  providedIn: 'root'
})
export class ScriptLoaderService {

  constructor(
    @Inject(PLATFORM_ID) private platformId: Object,
  ) {
  }

  load(scriptUrl: string) {
    if (isPlatformBrowser(this.platformId)) {
      let node: any = document.createElement('script');
      node.src = scriptUrl;
      node.type = 'text/javascript';
      node.async = true;
      node.charset = 'utf-8';
      document.getElementsByTagName('head')[0].appendChild(node);
    }
  }
}

1
อย่างใดรู้สึกนี้หลบ
มุสตาฟา

2

โซลูชันของ @ rahul-kumar ใช้งานได้ดีสำหรับฉัน แต่ฉันต้องการเรียกใช้ฟังก์ชันจาวาสคริปต์ใน typescript ของฉัน

foo.myFunctions() // works in browser console, but foo can't be used in typescript file

ฉันแก้ไขได้โดยการประกาศใน typescript ของฉัน:

import { Component } from '@angular/core';
import { ScriptService } from './script.service';
declare var foo;

และตอนนี้ฉันสามารถเรียกfooที่ใดก็ได้ในไฟล์ typecript ของฉัน


ถ้าฉันนำเข้าสคริปต์หลายตัว foo, foo1, foo2 และฉันรู้เฉพาะในช่วงเวลาของการดำเนินการวิธีการประกาศแบบไดนามิก?
natrayan

2

ในกรณีของฉันฉันโหลดjsและcss visjsไฟล์โดยใช้เทคนิคด้านบน - ซึ่งใช้งานได้ดี ฉันเรียกฟังก์ชั่นใหม่จากngOnInit()

หมายเหตุ:ฉันไม่สามารถโหลดได้โดยเพิ่มแท็ก<script>และ<link>แท็กลงในไฟล์เทมเพลต html

loadVisJsScript() {
  console.log('Loading visjs js/css files...');
  let script = document.createElement('script');
  script.src = "../../assets/vis/vis.min.js";
  script.type = 'text/javascript';
  script.async = true;
  script.charset = 'utf-8';
  document.getElementsByTagName('head')[0].appendChild(script);    
	
  let link = document.createElement("link");
  link.type = "stylesheet";
  link.href = "../../assets/vis/vis.min.css";
  document.getElementsByTagName('head')[0].appendChild(link);    
}


ฉันต้องการโหลดไฟล์ CSS จากแหล่งข้อมูลภายนอก ขณะนี้ฉันกำลังเผชิญกับข้อผิดพลาดว่า "ไม่อนุญาตให้โหลดทรัพยากรในท้องถิ่น" .. กรุณาแนะนำ
Karan

ฉันลองแบบนี้ แม้ว่ามันจะทำงานได้ดีสำหรับไฟล์สคริปต์ แต่มันก็ใช้ไม่ได้กับ Stylesheets
118218

2

สวัสดีคุณสามารถใช้ 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 (ที่)


1

@ d123546 ฉันประสบปัญหาเดียวกันและทำให้มันใช้งานได้ในขณะนี้โดยใช้ ngAfterContentInit (Lifecycle Hook) ในองค์ประกอบดังนี้:

import { Component, OnInit, AfterContentInit } from '@angular/core';
import { Router } from '@angular/router';
import { ScriptService } from '../../script.service';

@Component({
    selector: 'app-players-list',
    templateUrl: './players-list.component.html',
    styleUrls: ['./players-list.component.css'],
    providers: [ ScriptService ]
})
export class PlayersListComponent implements OnInit, AfterContentInit {

constructor(private router: Router, private script: ScriptService) {
}

ngOnInit() {
}

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

1
import { Injectable } from '@angular/core';
import * as $ from 'jquery';

interface Script {
    src: string;
    loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
    public _scripts: Script[] = [];

    /**
     * @deprecated
     * @param tag
     * @param {string} scripts
     * @returns {Promise<any[]>}
     */
    load(tag, ...scripts: string[]) {
        scripts.forEach((src: string) => {
            if (!this._scripts[src]) {
                this._scripts[src] = { src: src, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(src => promises.push(this.loadScript(tag, src)));

        return Promise.all(promises);
    }

    /**
     * Lazy load list of scripts
     * @param tag
     * @param scripts
     * @param loadOnce
     * @returns {Promise<any[]>}
     */
    loadScripts(tag, scripts, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        scripts.forEach((script: string) => {
            if (!this._scripts[script]) {
                this._scripts[script] = { src: script, loaded: false };
            }
        });

        const promises: any[] = [];
        scripts.forEach(script => promises.push(this.loadScript(tag, script, loadOnce)));

        return Promise.all(promises);
    }

    /**
     * Lazy load a single script
     * @param tag
     * @param {string} src
     * @param loadOnce
     * @returns {Promise<any>}
     */
    loadScript(tag, src: string, loadOnce?: boolean) {
        debugger;
        loadOnce = loadOnce || false;

        if (!this._scripts[src]) {
            this._scripts[src] = { src: src, loaded: false };
        }

        return new Promise((resolve, _reject) => {
            // resolve if already loaded
            if (this._scripts[src].loaded && loadOnce) {
                resolve({ src: src, loaded: true });
            } else {
                // load script tag
                const scriptTag = $('<script/>')
                    .attr('type', 'text/javascript')
                    .attr('src', this._scripts[src].src);

                $(tag).append(scriptTag);

                this._scripts[src] = { src: src, loaded: true };
                resolve({ src: src, loaded: true });
            }
        });
    }

    reloadOnSessionChange() {
        window.addEventListener('storage', function(data) {
            if (data['key'] === 'token' && data['oldValue'] == null && data['newValue']) {
                document.location.reload();
            }
        });
    }
}

0

ตัวอย่างสามารถ

ไฟล์ script-loader.service.ts

import {Injectable} from '@angular/core';
import * as $ from 'jquery';

declare let document: any;

interface Script {
  src: string;
  loaded: boolean;
}

@Injectable()
export class ScriptLoaderService {
public _scripts: Script[] = [];

/**
* @deprecated
* @param tag
* @param {string} scripts
* @returns {Promise<any[]>}
*/
load(tag, ...scripts: string[]) {
scripts.forEach((src: string) => {
  if (!this._scripts[src]) {
    this._scripts[src] = {src: src, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach((src) => promises.push(this.loadScript(tag, src)));

return Promise.all(promises);
}

 /**
 * Lazy load list of scripts
 * @param tag
 * @param scripts
 * @param loadOnce
 * @returns {Promise<any[]>}
 */
loadScripts(tag, scripts, loadOnce?: boolean) {
loadOnce = loadOnce || false;

scripts.forEach((script: string) => {
  if (!this._scripts[script]) {
    this._scripts[script] = {src: script, loaded: false};
  }
});

let promises: any[] = [];
scripts.forEach(
    (script) => promises.push(this.loadScript(tag, script, loadOnce)));

return Promise.all(promises);
}

/**
 * Lazy load a single script
 * @param tag
 * @param {string} src
 * @param loadOnce
 * @returns {Promise<any>}
 */
loadScript(tag, src: string, loadOnce?: boolean) {
loadOnce = loadOnce || false;

if (!this._scripts[src]) {
  this._scripts[src] = {src: src, loaded: false};
}

return new Promise((resolve, reject) => {
  // resolve if already loaded
  if (this._scripts[src].loaded && loadOnce) {
    resolve({src: src, loaded: true});
  }
  else {
    // load script tag
    let scriptTag = $('<script/>').
        attr('type', 'text/javascript').
        attr('src', this._scripts[src].src);

    $(tag).append(scriptTag);

    this._scripts[src] = {src: src, loaded: true};
    resolve({src: src, loaded: true});
  }
 });
 }
 }

และการใช้งาน

ฉีดครั้งแรก

  constructor(
  private _script: ScriptLoaderService) {
  }

แล้วก็

ngAfterViewInit()  {
this._script.loadScripts('app-wizard-wizard-3',
['assets/demo/default/custom/crud/wizard/wizard.js']);

}

หรือ

    this._script.loadScripts('body', [
  'assets/vendors/base/vendors.bundle.js',
  'assets/demo/default/base/scripts.bundle.js'], true).then(() => {
  Helpers.setLoading(false);
  this.handleFormSwitch();
  this.handleSignInFormSubmit();
  this.handleSignUpFormSubmit();
  this.handleForgetPasswordFormSubmit();
});
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.