项目

脚本与样式懒加载

您可以使用 @abp/ng.core 包中的 LazyLoadService,以简单明确的方式实现脚本和样式的懒加载。

开始使用

您无需在模块或组件级别提供 LazyLoadService,因为它已在根级别提供。您可以直接在组件、指令或服务中注入并立即使用它。

import { LazyLoadService } from '@abp/ng.core';
import { inject } from '@angular/core';

@Component({
  /* 此处为类的元数据 */
})
class DemoComponent {
  private lazyLoadService = inject(LazyLoadService);
}

使用方法

您可以使用 LazyLoadServiceload 方法在 DOM 的指定位置创建 <script><link> 元素,并强制浏览器下载目标资源。

如何加载脚本

load 方法的第一个参数需要一个 LoadingStrategy。如果您传递一个 ScriptLoadingStrategy 实例,LazyLoadService 将创建一个带有指定 src<script> 元素,并将其放置在指定的 DOM 位置。

import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core';
import { inject } from '@angular/core';

@Component({
  template: `
    <some-component *ngIf="libraryLoaded$ | async"></some-component>
  `
})
class DemoComponent {
  private lazyLoadService = inject(LazyLoadService);

  libraryLoaded$ = this.lazyLoadService.load(
    LOADING_STRATEGY.AppendAnonymousScriptToHead('/assets/some-library.js'),
  );
}

load 方法返回一个可观察对象,您可以在组件中或通过 async 管道订阅它。在上面的示例中,NgIf 指令仅在脚本成功加载或之前已加载时才会渲染 <some-component>

您可以在模板中多次使用 async 管道订阅。脚本只会被加载一次。

请参阅 LoadingStrategy 了解所有可用的加载策略以及如何构建自己的加载策略。

如何加载样式

如果您将 StyleLoadingStrategy 实例作为 load 方法的第一个参数传递,LazyLoadService 将创建一个带有指定 href<link> 元素,并将其放置在指定的 DOM 位置。

import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core';
import { inject } from '@angular/core';

@Component({
  template: `
    <some-component *ngIf="stylesLoaded$ | async"></some-component>
  `
})
class DemoComponent {
  private lazyLoadService = inject(LazyLoadService);

  stylesLoaded$ = this.lazyLoadService.load(
    LOADING_STRATEGY.AppendAnonymousStyleToHead('/assets/some-styles.css'),
  );
}

load 方法返回一个可观察对象,您可以在组件中或通过 AsyncPipe 订阅它。在上面的示例中,NgIf 指令仅在样式成功加载或之前已加载时才会渲染 <some-component>

您可以在模板中多次使用 async 管道订阅。样式只会被加载一次。

请参阅 LoadingStrategy 了解所有可用的加载策略以及如何构建自己的加载策略。

高级用法

您拥有相当大的自由度来定义懒加载的工作方式。以下是一个示例:

const domStrategy = DOM_STRATEGY.PrependToHead();

const crossOriginStrategy = CROSS_ORIGIN_STRATEGY.Anonymous(
  'sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh',
);

const loadingStrategy = new StyleLoadingStrategy(
  'https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css',
  domStrategy,
  crossOriginStrategy,
);

this.lazyLoad.load(loadingStrategy, 1, 2000);

此代码将创建一个带有指定 URL 和完整性哈希的 <link> 元素,将其插入到 <head> 元素的顶部,并在首次尝试失败后 2 秒重试一次。

一个常见的用例是在使用某个功能之前加载多个脚本和/或样式

import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core';
import { forkJoin } from 'rxjs';
import { inject } from '@angular/core';

@Component({
  template: `
    <some-component *ngIf="scriptsAndStylesLoaded$ | async"></some-component>
  `
})
class DemoComponent {
  private lazyLoad = inject(LazyLoadService);

  private stylesLoaded$ = forkJoin(
    this.lazyLoad.load(
      LOADING_STRATEGY.PrependAnonymousStyleToHead('/assets/library-dark-theme.css'),
    ),
    this.lazyLoad.load(
      LOADING_STRATEGY.PrependAnonymousStyleToHead('/assets/library.css'),
    ),
  );

  private scriptsLoaded$ = forkJoin(
    this.lazyLoad.load(
      LOADING_STRATEGY.AppendAnonymousScriptToHead('/assets/library.js'),
    ),
    this.lazyLoad.load(
      LOADING_STRATEGY.AppendAnonymousScriptToHead('/assets/other-library.css'),
    ),
  );

  scriptsAndStylesLoaded$ = forkJoin(this.scriptsLoaded$, this.stylesLoaded$);
}

RxJS 的 forkJoin 将并行加载所有脚本和样式,并仅在全部加载完成时发出信号。因此,当放置 <some-component> 时,所有必需的依赖项都将可用。

注意到我们将样式前置到文档头部了吗?这有时是必要的,因为您的应用程序样式可能会覆盖某些库样式。在这种情况下,您必须注意前置样式的顺序。它们将逐个放置,并且在前置时,最后放置的样式将位于顶部

另一个常见用例是按顺序加载依赖脚本

import { LazyLoadService, LOADING_STRATEGY } from '@abp/ng.core';
import { concat } from 'rxjs';
import { inject } from '@angular/core';

@Component({
  template: `
    <some-component *ngIf="scriptsLoaded$ | async"></some-component>
  `
})
class DemoComponent {
  private lazyLoad = inject(LazyLoadService);

  scriptsLoaded$ = concat(
    this.lazyLoad.load(
      LOADING_STRATEGY.PrependAnonymousScriptToHead('/assets/library.js'),
    ),
    this.lazyLoad.load(
      LOADING_STRATEGY.AppendAnonymousScriptToHead('/assets/script-that-requires-library.js'),
    ),
  );
}

在此示例中,第二个文件需要先加载第一个文件。RxJS 的 concat 函数将让您按给定顺序逐个加载所有脚本,并仅在全部加载完成时发出信号。

API

loaded

loaded: Set<string>

所有先前加载的路径都可通过此属性获取。它是一个简单的 JavaScript Set

load

load(strategy: LoadingStrategy, retryTimes?: number, retryDelay?: number): Observable<Event>
  • strategy 参数是这里的重点,上面已经解释过。
  • retryTimes 定义在失败前重试加载的次数(默认值:2)。
  • retryDelay 定义重试之间的延迟时间(默认值:1000)。
在本文档中