布莱恩F爱
从专注于角图,Web技术以yobet英雄联盟及波特兰的Node.js的Google开发人员专家中学习。
广告 ·ultimatecourses.com.
用终极课程学习角度正确的方式”></a>
          </div>
          <article class=

懒人负载角9+组件

Angular 9+的惰性加载组件变得简单多了!

前往角v9

以前,在Angular中惰性加载单个组件(而不是惰性加载的模块)需要理解Angular的底层api,有些人可能会说,有点神奇。

Angular版本9引入了一个名为“常春藤”的新渲染引擎。这取代了以前称为“查看渲染器”的先前渲染引擎。使用常春藤的API是用于角度的,制作它使用预先编译(AOT)更容易编译组件,然后可以在运行时惰性地、动态地加载和创建组件。

在Ivy和Angular版本9之前,我们必须:

  • 使用ngmodulefactoryloader.加载和编译模块,并为其提供依赖项的实例注射器
  • 然后我们使用resolveComponentFactory注入的方法ComponentFactoryResolver为它提供我们的组件实例。
  • 最后,我们可以创建和渲染组件通过createComponent ()的方法ViewContainerref.在dom。

为了简洁起见,我是将深入潜入延迟加载Angular V2至V8所需的代码的复杂性。相反,我会把你推荐给流行的hero-loader模块由队伍建造在希罗多维夫斯。

存储库

为了跟随,你需要结账v9-懒人组件存储库的分支:

Git.克隆https://github.com/blove/angular-v9.gitGit.结帐V9-Lazy-Components

演示

具有角度9和常春藤的懒惰装载组件”></p>
            <h2>现有的声明式组件</h2>
            <p>在本例中,我目前有一个<code>PlanetComponent.</code>实例,该实例显示与<code>行星</code>。我使用这个组件来显示一个人的家园。例如,卢克·天行者的母星塔图因。</p>
            <p>这是我目前正在实施的模板<code>PlanetComponent.</code>,位于<strong>src / app /功能/人/对话框/ person-home-planet-dialog / person-home-planet-dialog.component.html</strong>:</p>
            <div class=

<h1垫对话标题>{{data.person.fields.name}}:主行星h1><mat-dialog-content><SWR-星球(地球)=行星|异步>SWR-星球>mat-dialog-content><垫 - 对话框对齐=结束><按钮垫子按钮mat-dialog-close>关闭按钮>垫 - 对话框>

这是PlanetComponent.类,位于src / app /功能/人/主持人/地球/ planet.component.ts:

@组件({选择器:“swr-planet”,TemplateURL.:”。/ planet.component.html ',样式堡垒:('./planet.component.scss']})出口PlanetComponent.{/ **显示的星球。* /@输入()地球:行星;}

PlanetComponent.有一个接受行星来显示。

惰性加载组件

出于本练习的目的,我想惰性加载PlanetComponent.

首先,我们需要删除已声明的组件,我们将用一个< ng-template >元件:

<h1垫对话标题>{{data.person.fields.name}}:主行星h1><mat-dialog-content><ng-templation.>ng-templation.>mat-dialog-content><垫 - 对话框对齐=结束><按钮垫子按钮mat-dialog-close>关闭按钮>垫 - 对话框>

接下来,我们将访问ViewContainerref.与之相关< ng-container >使用@ViewChild()组件类中的装饰器。它位于src / app /功能/人/对话框/ person-home-planet-dialog / person-home-planet-dialog.component.ts:

出口personhomeplanetdialogcomponent.{/ ** Planet模板的View容器参考。* /@viewchild.(Templateref.,{:ViewContainerref.})私人planetTemplateViewContainerRef:ViewContainerref.;}

几件事要注意:

  • 首先,我们用@ViewChild()的视图查询Templateref.实例,我们使用< ng-template >元件。
  • 其次,我们指定了选择函数的第二个可选参数@ViewChild()装饰函数。此可选参数是一个对象,以及我们可以指定的属性之一是财产。
  • 属性使我们能够从视图查询指定其他令牌以返回。在这种情况下,我想要参考ViewContainerref.实例。
  • 我们将使用planetTemplateViewContainerRef类的属性指示渲染引擎在哪里渲染我们的惰性加载组件。

的实例注入ComponentFactoryResolver类。

出口personhomeplanetdialogcomponent.{/ ** Planet模板的View容器参考。* /@viewchild.(Templateref.,{:ViewContainerref.})私人planetTemplateViewContainerRef:ViewContainerref.;构造函数(私人只读的componentFactoryResolver:ComponentFactoryResolver){}}

根据文件,ComponentFactoryResolver是:

一个简单的注册表,将组件映射到生成的CompanicFactory类,该类可用于创建组件的实例。

下一步是:

  • 使用动态延迟加载组件包进口()函数。这个函数需要模块的路径并返回承诺如果已解决,则提供模块。
  • 使用ComponentFactoryResolver首先得到ComponentFactory.
  • 然后我们将使用createComponent ()我们的方法ViewContainerref.创建和呈现DOM中的组件。
  • 最后,我们可以使用返回值ComponentRef实例修改实例的属性。
出口personhomeplanetdialogcomponent.{/ ** Planet模板的View容器参考。* /@viewchild.(Templateref.,{:ViewContainerref.})私人planetTemplateViewContainerRef:ViewContainerref.;构造函数(私人只读的componentFactoryResolver:ComponentFactoryResolver){}私人lazyLoadPlanet(地球:行星):空虚{进口('../../presenters/planet/planet.component')然后(({PlanetComponent.})=>{常量组件=componentFactoryResolverresolveComponentFactory(PlanetComponent.);常量componentRef=planetTemplateViewContainerRefcreateComponent(组件);componentRef实例地球=地球;});}}

让我们快速回顾一下lazyLoadPlanet ()方法:

  • 首先,我们用进口()功能动态导入模块(ES6模块,而不是NgModule)。
  • 这回归A.承诺这与模块一起解决。
  • 我用对象解构来访问PlanetComponent.类导出到模块中的。
  • 使用resolveComponentFactory ()注射方法ComponentFactoryResolver类获取ComponentFactory.实例PlanetComponent.
  • 使用createComponent ()方法的方法planetTemplateViewContainerRef创建并呈现组件,该组件被追加到ViewContainerref.
  • createComponent ()方法返回A.ComponentRef实例,有一个实例属性,该属性引用组件实例。
  • 最后,我们指定了地球我们的财产PlanetComponent.实例提供必要的数据来显示信息的信息地球

以下是包含获取的完整源代码行星为了:

出口personhomeplanetdialogcomponent.实现了ondestroy,oninit.{/ ** Planet模板的View容器参考。* /@viewchild.(Templateref.,{:ViewContainerref.})planetTemplateViewContainerRef:ViewContainerref.;/**当组件被销毁时取消从可观察流的订阅。* /私人退订=主题();构造函数(私人只读的componentFactoryResolver:ComponentFactoryResolver,@注入(MAT_DIALOG_DATA)上市数据:{:},私人只读的planetService:行星服务){}ngOnDestroy(){退订下一个();退订完成();}ngOnInit(){planetServicegetPlanetForPerson(数据)(龙头(地球=>lazyLoadPlanet(地球)),take(退订))订阅();}私人lazyLoadPlanet(地球:行星):空虚{进口('../../presenters/planet/planet.component')然后(({PlanetComponent.})=>{常量组件=componentFactoryResolverresolveComponentFactory(PlanetComponent.);常量componentRef=planetTemplateViewContainerRefcreateComponent(组件);componentRef实例地球=地球;});}}

这就是我们使用Angular第9版惰性加载组件的方式!

延迟加载多个组件到模板中

在上面的例子中,您可能已经注意到我们正在使用Templateref.查询@ViewChild()访问这一点< ng-template >模板参考。如果您懒惰将多个组件加载到模板中,则此策略将无法正常工作。

这里的解决方案是使用多核< ng-container >带有模板引用变量的元素:

<ng-container.# personContainer>ng-container.><ng-container.#planetcontainer.>ng-container.>

我喜欢使用< ng-container >为此而不是污染DOM的元素

(或其他)的元素。

然后,我可以将模板参考变量名称指定给@ViewChild()查询获取ViewContainerref.对于每个容器:

出口personhomeplanetdialogcomponent.{/ **人员容器的视图集装箱参考。* /@viewchild.('人物联网',{:ViewContainerref.})私人personViewContainerRef:ViewContainerref.;/**行星容器的视图容器引用。* /@viewchild.(“planetContainer”,{:ViewContainerref.})私人planetViewContainerRef:ViewContainerref.;}

现在我可以根据需要延迟加载组件,然后在相应的情况下创建和呈现相应的组件ViewContainerref.

依赖关系

如果你的惰性加载组件有需要注入到组件类中的依赖项怎么办构造函数()函数?

答案是:

  • 如果已保证依赖性已通过该依赖性已加载提供者Array An.@ngmodule(),或透过providedIn课堂上的财产@Injectable ()装饰师,然后它应该只是工作。当然,如果没有提供依赖项,那么依赖项注入就会失败,错误如下:nullinjectorerror:XYZService没有提供者!
  • 如果还没有提供依赖项,那么我们可以指定提供者数组的@零件()惰性加载组件的元数据。

这是一个使用的例子提供者属性来为延迟加载的组件指定依赖项:

@组件({选择器:“swr-planet”,TemplateURL.:”。/ planet.component.html ',样式堡垒:('./planet.component.scss'],提供者:(filmservice.]})出口PlanetComponent.{/ **显示的星球。* /@输入()地球:行星;构造函数(filmService:filmservice.){}}

注意:

  • 使用提供者物业在@零件()装饰器我们可以指示依赖注入为此组件创建提供程序(以及在此级别的依赖树)。
  • 现在我们可以通过组件类的依赖注入这个依赖构造函数()函数。

模块

如果你的惰性加载组件依赖于其他模块怎么办?例如,如果你需要FormsModule.和/或反应omformodule如果你的组件是一个表单?

如果我们试图使用NgForm在我们的模板中,我们会得到一个错误:错误:没有找到带有exportAs 'ngForm'的指令。问题在于,我们的组件模板依赖于FormsModule.

答案是我们包含了ngmodule.在与组件相同的文件中指定必要的进口组件:

@组件({选择器:“swr-planet”,TemplateURL.:”。/ planet.component.html ',样式堡垒:('./planet.component.scss']})出口PlanetComponent.{/ **显示的星球。* /@输入()地球:行星;}@ngmodule.({宣言:(PlanetComponent.],进口:(FormsModule.,反应omformodule]})PlanetComponentModule.{}

注意:

  • PlanetComponent.依靠两种FormsModule.反应omformodule
  • 我们创造了一个ngmodule.在与延迟加载的组件相同的文件中。
  • 我们指定的宣言属性引用组件类;在这种情况下PlanetComponent.类。
  • 我们指定的进口具有需要导入延迟加载组件的模块数组的属性。

结论

使用Angular Version 9和新的常春藤编译和渲染管道我们可以延迟加载,创建和渲染角分量。

布莱恩F爱

嗨,我是布莱恩。我对类型名称,Angular和node.js感兴趣我嫁给了我最好的朋友邦妮,我住在波特兰和我滑雪(很多)。