【问题标题】:Dynamically creating lazy loaded components in angular-2在 angular-2 中动态创建延迟加载的组件
【发布时间】:2017-12-13 08:39:51
【问题描述】:

我们在 cms (Sitecore) 中托管 angular2 应用程序,我们要求内容编辑器可以在页面中添加、删除和重新排序我们应用程序的组件,他们还可以根据需要添加其他组件。

我们通过让 cms 生成脚本标签来加载我们的组件来做到这一点。生成的html的一个例子是:

<body>
    <sales-root></sales-root>
    <script type="text/html" id="generated-header">
        <sales-welcome></sales-welcome>
    </script>
    <script type="text/html" id="generated-content">
        <sales-personal-info></sales-personal-info>
        <div><!-- regular html content --></div>
    </script>
</body>

在我们的sales-root 组件中

export class AppComponent extends Translation implements OnInit {
    @ViewChild('header', { read: ViewContainerRef }) headerRef;
    @ViewChild('content', { read: ViewContainerRef }) contentRef;

    ngOnInit() {
        this.loadSitecorePlaceholders(this.headerRef, 'generated-header');
        this.loadSitecorePlaceholders(this.contentRef, 'generated-content');
        // ...
    }
    private loadSitecorePlaceholders(containerRef: ViewContainerRef, placeholder: string) {
        // get the generated components listed from the sitecore placeholder
        const generatedContent = this.elementRef.nativeElement.parentNode.children[placeholder];
        if (generatedContent === undefined) { return; }
        if (containerRef === undefined) { return; }

        this.createComponentService.createComponentsFromHtml(containerRef, generatedContent.innerText);

        // we've finished creating all the components we need, remove the nodes created by sitecore.
        this.elementRef.nativeElement.parentNode.removeChild(generatedContent);
    }
}

CreateComponentService 中,我们初始化了一组允许的组件工厂,以及一个通用的htmlHost 组件工厂:

this._selectableFactories = creatableComponents
    .map((component: Type<any>) =>
        this.componentFactoryResolver.resolveComponentFactory(component));

我们为选择器解析 CMS 生成的脚本标签,如果我们找到它们,我们就添加组件,或者注入通用 html 组件:

private createAngularComponent(
    container: ViewContainerRef,
    factory: ComponentFactory<Type<any>>,
    element: HTMLElement,
) {
    const selector = factory.selector.toLocaleLowerCase();
    container.createComponent(factory);
    // ...
}

private createHtmlComponent(container: ViewContainerRef, element: HTMLElement) {
    const component = container.createComponent(this.htmlHostFactory).instance;
    component.content = element.outerHTML;
}

除了性能之外,所有这些都运行良好。我们有许多组件,加载和编译它们都需要一段时间(在快速机器上需要 3 到 4 秒)。我们通过两种方式解决这个问题:

  1. 转向 AOT 而不是 JIT。由于内部库而被证明存在问题,但我们正在解决它。
  2. 根据需要延迟加载组件。我们只需要任何页面上的组件子集,因此这应该会给我们带来一些好处。

对于#2,我们需要在entryComponents 中列出@NgModule 中的所有可创建组件,因此它们必须在生成时都存在......对吗?我还预加载了工厂,以便我可以找到选择器,但我可以在开发中构建该列表。

理想情况下,我有一个惰性组件工厂工厂的选择器字典,第一次调用会下载组件并加载它然后注入它,这将发生在 ngInit 之后,并且还会呈现出更快的加载速度。

是否可以延迟加载组件?到目前为止,我看到的所有示例都是使用路由器,而我们不是由于动态组合。 怎么样?

【问题讨论】:

  • 嘿,my answer 有帮助吗?
  • 嗨@Maximus,它看起来不错,但是我还没有机会实现它,其他紧迫的项目问题:/我会在今天或周末尝试解决它,谢谢寻求帮助。
  • 怎么样?

标签: angular typescript lazy-loading


【解决方案1】:

你有几个选择

1) 将延迟加载的组件添加到它们自己的模块中,并按照Here is what you need to know about dynamic components in Angular 中的描述按需加载和编译这些组件。您将需要使用compileModuleAndAllComponentsAsync 方法。示例如下:

ngAfterViewInit() {
  System.import('app/t.module').then((module) => {
      _compiler.compileModuleAndAllComponentsAsync(module.TModule)
        .then((compiled) => {
          const m = compiled.ngModuleFactory.create(this._injector);
          const factory = compiled.componentFactories[0];
          const cmp = factory.create(this._injector, [], null, m);
        })
    })
}

2) 另一种方法是 AOT 编译组件并按需加载它们的工厂。 Angular AOT 编译器将 AOT 输出生成为有效的 ES6/TS 模块,因此您可以单独导入组件并直接从工厂创建它们的实例:

  System.import('components/ex.component.ngfactory').then((factory) => {
       const cmp = factory.create(this._injector, [], null, m);
  })

或者您可以获取包含所有组件的模块工厂并在其实例中创建。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-11-02
    • 1970-01-01
    • 1970-01-01
    • 2018-07-05
    • 1970-01-01
    • 2016-05-23
    • 1970-01-01
    相关资源
    最近更新 更多