前言
上周写代码始终呈现因为模块,或者其余的援用谬误而导致局部性能无奈正常化的状况,一开始老师让看教程,也是看的挺懵的,起初老师给讲了一下之后才真正晓得是怎么回事了.
组建的基本要素
组建必然存在模块当中,个别状况下如果间接在命令行中输出ng g c app,则会生成名为app的一个angular组建,也就是以下四种文件
1是v层的html款式文件,2是模版的v层html代码文件,3是单元测试的代码文件,4则为组建的c层文件,咱们在外面定义了咱们的1和2文件.其中4是必选的,其余三个都是可选的.有组建必须有模块,组建肯定是生存在模块外面的,模块就是组建因素加上一个.module.ts的文件.
组建须要的能力
说完组建的几因素,那当初来说说咱们从哪晓得以及咱们须要给组建提供什么能力才可能让此组建顺利跑起来.
构造函数中
在4文件外面,也就是组建的c层,在4文件外面往往是一个class 类,既然有类,那么就会有构造函数吧,好的,那么构造函数就是一种路径,比方下图:
能够看到,如果想要让此构造函数所在的类编一部报错,咱们就须要实例化TownService、CommonService、ActivatedRoute、Router,这四个类,而如果咱们想要实例化这四个类咱们有须要从哪去找呢,同样,也是从构造函数中去找,比方ToenService:
能够看到咱们如果想要实例化TownService,那我咱们就必须提供HttpClient这个货色,从哪提供呢,或者说怎么实例化,实例化须要哪些货色呢,咱们能够在此indexComponent所在的模块中引入HttpClientModule(ng s时须要),单元测试文件中援用HttpClientTestingModule(ng t时用)从而保障咱们在类TownService的失常实例化,从而失常实例化indexComponent.下一个,同样的情理上面三个也是须要看相应构造函数中须要什么能力,此为CommonService的构造函数,那咱们就须要提供Router以及DomSanitizer了,然而呢,DomSanitizer不属于哪个模块中,所以只需呀在以后文件申明其命名空间即可.因为ActivatedRoute和Router不须要其余能力咱们就间接引他们所在的模块即可.
V层代码中
<div> <div class="col-12 text-right"> <a class="btn btn-primary" routerLink="add"><i class="fas fa-plus"></i>新增</a> </div></div><app-size [size]="pageData.size" (changeSize)="onSizeChange($event)"></app-size><table class="table table-striped mt-2"> <thead> <tr class="table-primary"> <th>序号</th> <th>名称</th> <th>拼音</th> <th>操作</th> </tr> </thead> <tbody> <tr *ngFor="let object of pageData.content; index as i"> <td>{{i + 1}}</td> <td>{{object.name}}</td> <td>{{object.pinyin}}</td> <td> <span class="btn btn-outline-primary btn-sm" routerLink="edit/{{object.id}}"> <i class="fas fa-pen"></i> 编辑 </span> <span class="btn btn-outline-primary btn-sm" (click)="onDelete(i, object.id)"> <i class="fas fa-trash-alt"></i> 删除 </span> </td> </tr> </tbody></table><app-page [page]="pageData.number" [size]="pageData.size" [totalElements]="pageData.totalElements" (changePage)="onPageChange($event)"></app-page>
能够看到我V层代码中含有angular特有的标签属性routerLink,以及援用size和page模版的代码,如果咱们不给予组建相应的能力的话那么组建是不意识他的,天然也不会通过编译,所以咱们须要引入RouterTestingModule来赋予组建辨认routerLink的能力,当然要使得编译器不报错咱们还须要引入PageModule以及SizeModule.
最终单元测试援用代码
// 申明,此处为组建 declarations: [IndexComponent], // 引入,此处为模块 imports: [ // 路由器测试模块,设置用于测试的路由器。 RouterTestingModule, // 援用了commonModule PageModule, // 援用了commonModule和FormsModule SizeModule, // ApiTestingModule中引入了HttpClientModule,HttpClientModule中提供了HttpClient, // 这使得 IndexComponet -> TownService 中的HttpClient可用 ApiTestingModule ]
看到这里是不是会好奇,为什么没有提供CommonService,HttpClient...如果你好奇了那请接着往下看吧!
援用的优先级
咱们能够看到其实咱们往往是一个类会呈现在不只一个构造函数中那是不是须要实例化多个类呢,其实不是的,angular只实例化一个类,须要他的类共用他即可,而且是前面笼罩后面的.比如说咱们看到在CommonService和IndexComponent中都须要Router,而IndexComponent又须要CommonService,所以笔者猜想是编译器先后初始化了两个Router,当第二个呈现的时候,就会笼罩第一个,所以实际上IndexComponent和CommonService用的是一个Router,正所谓后者笼罩前者.当然为什么没有援用HttpClientModule.
援用的私有和公有
咱们能够援用咱们想要的货色,然而咱们援用之后那些援用咱们的人如果须要雷同的货色他们还须要再援用一次吗,这就波及到了援用的公有与私有.
declarations
declarations意为申明,个别状况下咱们会在这个外面申明组建、指令和管道,应用declarations援用的都是公有的,即咱们援用的组建、指令和管道之后这些在咱们组建外面就会变成公有的,也就意味着下一个援用咱们的人是不可能拜访的,如果他们也须要同样的货色他们也须要再引一遍.
imports
imports意为引进,我么会把咱们须要的模块全副放到他的外面,当然模块通过它引进来之后,同样也就变成了公有的,如同declarations一样.
providers
providers意为提供者,写法为
providers: [ {provide: CommonService, useClass: CommonStubService}]
意为如果有CommonService,那么就用CommonService提供,如果没有那么就用类CommonStubService提供,当然useClass的地位还能够是useValue(提供值), useFactory(提供工厂)和useExisting(提供别名).
providers是公有制,即如果A提供了123,B提供了456,那么C同时援用A和B那么C就有了123456,和以上两种是不同的.
exports
exports意为进口,与imports含意相同,应用它能够将组建进口,即申明为私有类型,使得引入咱们本人的组建能够应用咱们进口的组建,例如:
@NgModule({ declarations: [PageComponent], imports: [ CommonModule ], exports: [PageComponent]})export class PageModule {}
PageModule将PageComponent组建申明为私有的,即别的组建能够间接援用的.当然SizeModule也是这样的.
回顾援用悬案
咱们之所以没有援用CommonService的提供者是因为
@NgModule({ imports: [ HttpClientModule ], providers: [ {provide: CommonService, useClass: CommonStubService}, { provide: HTTP_INTERCEPTORS, multi: true, useClass: MockApiTestingInterceptor.forRoot(apis) }]})export class ApiTestingModule {}
咱们能够看到咱们在单元测试援用的ApiTestingModule中曾经用CommonStubService provide了一个CommonSerivce了,此时咱们须要实例化的就变成了CommonStubService,那咱们就须要看看CommonStubService 到底须要什么了.
能够看到咱们CommonStubService须要的是Router、DomSanitizer、ActivedRoute,我么有Router和ActivedRoute的提供者RoutingTestingModule的,DomSanitizer不属于模块,只须要引入命名空间.到当初CommonStubService实例化结束,代替了CommonService.然而咱们依然须要实例化CommonService,因为咱们的CommonStubService继承了CommonService,当初咱们还须要的是HttpClient的能力吧,当然咱们也是有的,就在咱们的ApiTestingModule中引入了HttpClient这个组建,大快人心,至此咱们的两个类实例化胜利!
总结
1、组建的所须要以及具备的能力要去找C层构造函数,V层代码.
2、被写道imports、declarations外面之后即变为公有,在providers外面为私有,exports能够申明为私有.
3、援用是能够被笼罩的,即后来者居上,后来者会笼罩掉之前的