乐趣区

关于angular:Angular组建需要以及拥有的能力

前言

上周写代码始终呈现因为模块, 或者其余的援用谬误而导致局部性能无奈正常化的状况, 一开始老师让看教程, 也是看的挺懵的, 起初老师给讲了一下之后才真正晓得是怎么回事了.

组建的基本要素

组建必然存在模块当中, 个别状况下如果间接在命令行中输出 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、援用是能够被笼罩的, 即后来者居上, 后来者会笼罩掉之前的

退出移动版