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的类和对象,比如:字符串、数字、函数、实体模型、配置、业务逻辑和辅助类。
angular2-模块的更多相关文章
- 浅谈angular2+ionic2
浅谈angular2+ionic2 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2 ...
- Angular2 NgModule
1. 说明 典型的模块是一个内聚的代码块,用来实现某种单一的功能.Angular2应用程序本质上是有一系列模块组成的,而且Angular 本身就是一组模块库.模块主要是导出一些东西——类,函数,值,供 ...
- 初识Angular2
Angular2是面向未来的科技,要求浏览器支持ES6+,我们现在要尝试的话,需要加一些 垫片来抹平当前浏览器与ES6的差异: angular2-polyfills - 为ES5浏览器提供ES6特性支 ...
- angular2+ionic2架构介绍
不要用angular的语法去写angular2,有人说二者就像Java和JavaScript的区别. 1. 项目所用:angular2+ionic2+typescript 2. 项目结构 3. S ...
- angualar2——八大组成
Angular2 模块 理解: Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules. 组件 组件是一个项目主干,一个模块由多个 ...
- AngularJS2.0教程(一)快速上手之基础知识
Why Angular2 Angular1.x显然非常成功,那么,为什么要剧烈地转向Angular2? 性能的限制 AngularJS当初是提供给设计人员用来快速构建HTML表单的一个内部工具.随着时 ...
- AngularJS2.0起步
ES6工具链 要让Angular2应用跑起来不是件轻松的事,因为它用了太多还不被当前主流浏览器支持的技术.所以,我们需要一个工具链:
- 浅谈Ionic2
http://www.cnblogs.com/zhouming-web/p/6226323.html 前言: 不要用angular的语法去写angular2,有人说二者就像Java和JavaScrip ...
- AngularJS2.0 hello world例子——引入这么多额外的依赖库真是很忧伤啊
初识Angular2 写一个Angular2的Hello World应用相当简单,分三步走: 1. 引入Angular2预定义类型 import {Component,View,bootstrap} ...
- Angular2 小贴士 NgModule 模块
angular2 具有了模块的概念,响应了后台程序的号召,高内聚 低耦合.模块就是用来进行封装,进行高内聚 低耦合的功能. 其实各人认为ng2 的模块和.net的工程类似,如果要使用模块中定义的功能 ...
随机推荐
- win10在CMD操作MySQL时中文显示乱码
根据网上说明直接修改数据库各种的字符集没有效果,后来经过测试发现需要先更换至旧版CMD才行. 具体总流程如下: 1.在边框栏上右键,打开属性栏. 2.选择“使用旧版控制台” 3.重启CMD,并设置字符 ...
- Qt 学习之路 2(52):使用拖放
Qt 学习之路 2(52):使用拖放 豆子 2013年5月21日 Qt 学习之路 2 17条评论 拖放(Drag and Drop),通常会简称为 DnD,是现代软件开发中必不可少的一项技术.它提供了 ...
- zTree学习笔记
一.zTree的下载 官网:http://www.treejs.cn/v3/main.php#_zTreeInfo 解压后的目录结构为: 二.zTree入门案例 2.1 在页面中引入相关文件 要使用z ...
- 【算法笔记】B1042 字符统计
1042 字符统计 (20 分) 请编写程序,找出一段给定文字中出现最频繁的那个英文字母. 输入格式: 输入在一行中给出一个长度不超过 1000 的字符串.字符串由 ASCII 码表中任意可见字符及空 ...
- leetcode 75 Sort Colors 计数排序,三路快排
解法一:计数排序:统计0,1,2 的个数 时间复杂度:O(n) 空间复杂度:O(k) k为元素的取值范围, 此题为O(1) class Solution { public: void sortC ...
- Week 3: Structured Types 5. Tuples and Lists Exercise: odd tuples
Exercise: odd tuples 5/5 points (graded) ESTIMATED TIME TO COMPLETE: 5 minutes Write a procedure cal ...
- i2c设备驱动之设备地址
第一步:查找设备的数据手册可得到设备的从机地址.读写地址. 很不巧的是我在这里又卡了近一天,由于自己的硬件知识学得相当的那啥,哎,没办法,怨不得别人. 今天终于开窍了!!!!! 在开始条件(S)后,发 ...
- MBR为什么不支持3T硬盘
MBR,全称为Master Boot Record,即硬盘的主引导记录.(是管理硬盘分区的一种模式.升级版是GPT) MBR保存在硬盘的第1个扇区(即硬盘的0柱面.0磁头.1扇区).它由三个部分组成, ...
- 通过 rundll32 创建设置注册表项权限
[Version]SIGNATURE="$Windows NT$" [DefaultInstall]AddReg=test.reg [test.reg]HKLM,"SOF ...
- PIE SDK打开长时间序列数据
1. 功能简介 时间序列数据(time series data)是在不同时间上收集到的数据,这类数据是按时间顺序收集到的,用于所描述现象随时间变化的情况.当前随着遥感卫星技术日新月异的发展,遥感卫星的 ...