Angular 9+的惰性加载组件变得简单多了!
以前,在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
<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.})=>{常量组件=这。componentFactoryResolver。resolveComponentFactory(PlanetComponent.);常量componentRef=这。planetTemplateViewContainerRef。createComponent(组件);componentRef。实例。地球=地球;});}}
让我们快速回顾一下lazyLoadPlanet ()
方法:
进口()
功能动态导入模块(ES6模块,而不是NgModule)。承诺
这与模块一起解决。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(){这。planetService。getPlanetForPerson(这。数据。人)。管(龙头(地球=>这。lazyLoadPlanet(地球)),take(这。退订))。订阅();}私人lazyLoadPlanet(地球:行星):空虚{进口('../../presenters/planet/planet.component')。然后(({PlanetComponent.})=>{常量组件=这。componentFactoryResolver。resolveComponentFactory(PlanetComponent.);常量componentRef=这。planetTemplateViewContainerRef。createComponent(组件);componentRef。实例。地球=地球;});}}
这就是我们使用Angular第9版惰性加载组件的方式!
在上面的例子中,您可能已经注意到我们正在使用Templateref.
查询@ViewChild()
访问这一点< ng-template >
模板参考。如果您懒惰将多个组件加载到模板中,则此策略将无法正常工作。
这里的解决方案是使用多核< ng-container >
带有模板引用变量的元素:
<ng-container.# personContainer>ng-container.><ng-container.#planetcontainer.>ng-container.>
我喜欢使用 然后,我可以将模板参考变量名称指定给 现在我可以根据需要延迟加载组件,然后在相应的情况下创建和呈现相应的组件 如果你的惰性加载组件有需要注入到组件类中的依赖项怎么办 答案是: 这是一个使用的例子 注意: 如果你的惰性加载组件依赖于其他模块怎么办?例如,如果你需要 如果我们试图使用 答案是我们包含了 注意: 使用Angular Version 9和新的常春藤编译和渲染管道我们可以延迟加载,创建和渲染角分量。 嗨,我是布莱恩。我对类型名称,Angular和node.js感兴趣我嫁给了我最好的朋友邦妮,我住在波特兰和我滑雪(很多)。< 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.
类。进口
具有需要导入延迟加载组件的模块数组的属性。结论
布莱恩F爱