angular2-模块
Angular模块 (NgModule)
Angular 模块是带有 @NgModule 装饰器函数的类。 @NgModule接收一个元数据对象,该对象告诉 Angular 如何编译和运行模块代码。 它标记出该模块拥有的组件、指令和管道, 并把它们的一部分公开出去,以便外部组件使用它们。 它可以向应用的依赖注入器中添加服务提供商
模块是组织应用和使用外部库扩展应用的最佳途径。
很多 Angular 库都是模块,例如:FormsModule、HttpModule、RouterModule。 很多第三方库也封装成了 Angular 模块,例如:Material Design、 Ionic、 AngularFire2。
模块可能在应用启动时主动加载,也可能由路由器进行异步惰性加载。
@NgModule装饰器用来为模块定义元数据。 我们先凭直觉来理解一下元数据
AppModule没有声明过NgIf指令,但该应用仍然能正常编译和运行。为什么这样没问题呢?
Angular 能识别NgIf指令,是因为我们以前导入过它。最初版本的AppModule就导入了BrowserModule
导入BrowserModule会让该模块公开的所有组件、指令和管道在AppModule下的任何组件模板中可用
更准确的说,NgIf是在来自@angular/common的CommonModule中声明的。
CommonModule提供了很多应用程序中常用的指令,包括NgIf和NgFor等。
BrowserModule导入了CommonModule并且重新导出了它。 最终的效果是:只要导入BrowserModule就自动获得了CommonModule中的指令。
很多熟悉的 Angular 指令并不属于CommonModule。 例如,NgModel和RouterLink分别属于 Angular 的FormsModule模块和RouterModule模块。 在使用那些指令之前,我们也必须导入那些模块
不要把NgModel(或FORMS_DIRECTIVES)加到 AppModule 元数据的declarations数据中!这些指令属于FormsModule`。
组件、指令和管道只能属于一个模块。
永远不要再次声明属于其它模块的类。
如果有两个同名指令,都叫做HighlightDirective,该怎么办呢?
我们只要在 import 时使用as关键字来为第二个指令创建个别名就可以了。
import { HighlightDirective as ContactHighlightDirective } from './contact/highlight.directive';
在组件中可以注入服务,但是那样一来,它的作用范围就会仅局限于该组件及其子组件, 想共享,要添加到AppModule元数据的providers列表中
全应用范围的提供商
ContactService的提供商是全应用范围的,这是因为 Angular 使用该应用的根注入器注册模块的providers。
从架构上看,ContactService属于“联系人”这个业务领域。 其它领域中的类并不需要知道ContactService,也不会要求注入它。
我们可能会期待 Angular 提供一种模块范围内的机制来保障此设计。 但它没有。与组件不同,Angular的 模块实例并没有它们自己的注入器,所以它们也没有自己的供应商范围。
Angular是故意这么设计的。 Angular的模块设计,主要目的是扩展应用程序,丰富其模块化能力。
在实践中,服务的范围很少会成为问题。 联系人之外的组件不会意外注入ContactService服务。 要想注入ContactService,你得先导入它的类型。 而只有联系人组件才会导入ContactService类型。
特性模块
- 随着一个个类被加入应用中,根模块
AppModule变大了。
- 我们遇到了指令冲突。 联系人模块的
HighlightDirective在AppModule中声明的HighlightDirective的基础上进行了二次上色。 并且,它染了应用标题文字的颜色,而不仅仅是ContactComponent中的。
- 该应用在联系人和其它特性区之间缺乏清晰的边界。 这种缺失,导致难以在不同的开发组之间分配职责。
- 特性模块技术来缓解此问题
特性模块是带有@NgModule装饰器及其元数据的类,就像根模块一样。 特性模块的元数据和根模块的元数据的属性是一样的。
根模块和特性模块还共享着相同的执行环境。 它们共享着同一个依赖注入器,这意味着某个模块中定义的服务在所有模块中也都能用。
import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';import { AwesomePipe } from './awesome.pipe';import { ContactComponent } from './contact.component';
import { ContactService } from './contact.service';
import { HighlightDirective } from './highlight.directive';@NgModule({imports: [ CommonModule, FormsModule ],declarations: [ ContactComponent, HighlightDirective, AwesomePipe ],exports: [ ContactComponent ],providers: [ ContactService ]
})
export class ContactModule { }
当前模块不会继承其它模块中对组件、指令或管道的访问权。 AppModule中的 imports 与 ContatModule的 imports 互不相干。 如果ContactComponent要绑定到[(ngModel)],它所在的ContactModule必需导入FormsModule。
我们还用CommonModule替换了BrowserModule,其中缘由参见这条常见问题
我们导出了ContactComponent,这样其它模块只要导入了ContactModule,就可以在它们的组件模板中使用ContactComponent了。
声明的所有其它联系人类默认都是私有的。 AwesomePipe和HighlightDirective对应用的其它部分是不可见的。 所以HighlightDirective不能把AppComponent的标题文字染色
app.module.ts
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';/* App Root */
import { AppComponent } from './app.component';
import { HighlightDirective } from './highlight.directive';
import { TitleComponent } from './title.component';
import { UserService } from './user.service';/* Contact Imports */
import { ContactModule } from './contact/contact.module';@NgModule({imports: [ BrowserModule, ContactModule ],declarations: [ AppComponent, HighlightDirective, TitleComponent ],providers: [ UserService ],bootstrap: [ AppComponent ],
})
export class AppModule { }
改进之处
修改后的AppModule有一些很棒的特性。
-
-
它不会再随着联系人的领域扩张而修改。
-
只有当添加新模块时才需要修改它。
-
它也变得简单了:
-
更少的
import语句 -
不再导入
FormsModule -
没有与联系人有关的声明
-
没有
ContactService提供商 -
没有
HighlightDirective冲突
-
-
路由使用惰性加载语法来告诉路由器要到哪里去找这些模块。
{ path: 'crisis', loadChildren: 'app/crisis/crisis.module#CrisisModule' },
{ path: 'heroes', loadChildren: 'app/hero/hero.module#HeroModule' }
惰性加载模块的位置是字符串而不是类型。 在本应用中,该字符串同时标记出了模块文件和模块类,两者用#分隔开。
路由到特性模块
src/app/contact目录中也有一个新文件contact-routing.module.ts。 它定义了我们前面提到过的联系人路由,并提供了ContactRoutingModule,就像这样:
@NgModule({imports: [RouterModule.forChild([{ path: 'contact', component: ContactComponent }])],exports: [RouterModule]
})
export class ContactRoutingModule {}
这次我们要把路由列表传给RouterModule的forChild方法 (总是在特性路由模块中调用RouterModule.forChild。)
ContactModule已经做了两个微小但重要的细节改动: imports: [ CommonModule, FormsModule, ContactRoutingModule ],
-
-
它从
contact-routing.module.ts中导入了ContactRoutingModule对象 -
它不再导出
ContactComponent
-
现在我们通过路由器导航到 ContactComponent,所以也就没有理由公开它了。它也不再需要选择器 (selector)。 也没有模板会再引用ContactComponent。它从 AppComponent 模板中彻底消失了。
哪些类不应该加到declarations中?
只有可声明的类才能加到模块的declarations列表中。
不要声明:
-
已经在其它模块中声明过的类。无论它来自应用自己的模块(@NgModule)还是第三方模块。
-
从其它模块中导入的指令。例如,不要声明来自
@angular/forms的FORMS_DIRECTIVES。 -
模块类
-
服务类
-
非Angular的类和对象,比如:字符串、数字、函数、实体模型、配置、业务逻辑和辅助类。
转载于:https://www.cnblogs.com/vs1435/p/7810123.html
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
