ng-docs / ng-docs.github.io

Angular 官方文档中文版预编译网站
https://angular.cn
Other
103 stars 22 forks source link

angular7+中如何动态加载第三方插件?根据需求,如何动态地加载某个静态js文件,并通过什么方式监测到该文件加载完成? #87

Open keepingT opened 5 years ago

wszgrcy commented 5 years ago

impoort('路径').then((res)=>{}) 如果js文件是模块化的,返回res应该是这个模块的引用 如果编译时报错,他会有个提示,让你把ts.config模块改成esnext,改完了就好了

Feng-JY commented 5 years ago

参考:https://github.com/NG-ZORRO/ng-zorro-antd/blob/master/scripts/site/_site/doc/app/app.component.ts#L202

yy7054wyq5 commented 5 years ago
import { Injectable, Inject } from '@angular/core';
import { Observable, ReplaySubject, Observer } from 'rxjs';

import { DOCUMENT } from '@angular/common';
import { HttpClient } from '@angular/common/http';

export function request(url: string) {
  return new Promise((resolve, reject) => {
    const oReq = new XMLHttpRequest();
    // https://caniuse.com/#search=XMLHttpRequest
    // ie11不支持json
    // oReq.responseType = 'json';
    oReq.onload = () => {
      let res;
      try {
        res = JSON.parse(oReq.response);
      } catch (error) {
        res = oReq.response;
      }
      if (oReq.status === 200) {
        resolve(res);
      } else {
        reject(res);
      }
      // console.log(res);
    };
    oReq.onerror = err => {
      reject(err);
    };
    oReq.open('get', url, true);
    oReq.send();
  });
}

@Injectable({
  providedIn: 'root'
})
export class LazyLoadingLibService {
  private loadedLibraries: { [url: string]: ReplaySubject<any> } = {};

  constructor(@Inject(DOCUMENT) private readonly document: any, private http: HttpClient) { }

  /**
   * 加载资源
   *
   * @private
   * @param {string} url
   * @param {Function} cb
   * @returns {Observable<any>}
   * @memberof LazyLoadingLibService
   */
  private _load(url: string, cb: () => Element): Observable<any> {
    if (this.loadedLibraries[url]) {
      return this.loadedLibraries[url].asObservable();
    }
    this.loadedLibraries[url] = new ReplaySubject();
    const element = cb();
    // 骚操作
    // 先用原生方法获取url的资源,若失败则返回错误
    // https://stackoverflow.com/questions/28556398/how-to-catch-neterr-connection-refused
    return new Observable((ob: Observer<any>) => {
      request(url).then(() => {
        this.document.body.appendChild(element);
        this.loadedLibraries[url].subscribe(() => {
          ob.next('');
          ob.complete();
        });
      }).catch(err => {
        this.loadedLibraries[url] = null;
        console.error('LazyLoadingLibService error', err);
        ob.error(err);
        ob.complete();
      });
    });
  }

  /**
   * 加载JS
   *
   * @param {string} url
   * @returns {Observable<any>}
   * @memberof LazyLoadingLibService
   */
  public loadJS(url: string): Observable<any> {
    return this._load(url, () => {
      const script = this.document.createElement('script');
      script.type = 'text/javascript';
      script.src = url;
      script.onload = () => {
        this.loadedLibraries[url].next('');
        this.loadedLibraries[url].complete();
      };
      return script;
    });
  }

  /**
   * 加载CSS
   *
   * @param {string} url
   * @returns
   * @memberof LazyLoadingLibService
   */
  public loadCSS(url: string) {
    return this._load(url, () => {
      const link = this.document.createElement('link');
      link.rel = 'stylesheet';
      link.href = url;
      link.onload = () => {
        this.loadedLibraries[url].next('');
        this.loadedLibraries[url].complete();
      };
      return link;
    });
  }
}