Angular 模块都是一个带有@NgModule装饰器的类。
NgModule是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。把紧随其后的类标记为模块类。其中最重要的属性是:
- declarations
声明本模块中拥有的视图类。包括[组件]、[指令]和[管道]。 - exports(根模块则不需要导出任何东西。)
导出可用于其它模块的组件[模板]。 - imports(Angular模块)
本模块声明的组件模板需要的类所在的其它模块。 - providers
[服务]的创建者,并加入到全局服务列表中,可用于应用任何部分。 - bootstrap
指定应用的主视图(称为根组件),它是所有其它视图的宿主。只有根模块才能设置bootstrap属性。
app.module.ts中bootstrap了AppComponent,而main.ts文件中bootstrap了AppModule
元数据告诉 Angular 如何处理一个类。我们用装饰器 (decorator) 来附加元数据。@Component装饰器,它把紧随其后的类标记成了组件类。
@Component的配置项包括:
selector:CSS 选择器,在父级 HTML 中查找对应内容,创建并插入该组件。
<li>{{hero.name}}</li> 插值绑定
<hero-detail [hero]="selectedHero"></hero-detail> 属性绑定
<li (click)="selectHero(hero)"></li> 事件绑定
<input [(ngModel)]="hero.name"> 双向绑定
组件是一种特殊的指令
“依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务
@Injectable()
变量赋值的方式初始化组件,也可以使用构造函数来声明和初始化属性。
插值表达式
<img title="{{heroImageUrl}}">
等价于
<img [title]="heroImageUrl">
等价于
<img bind-title="heroImageUrl">
其他同理
事件绑定
<button (click)="onSave()">Save</button>等价于
<button on-click="onSave()">On Save</button>
<div (myClick)="clickMessage=$event" clickable>click with myClick</div>
<button (click)="onSave($event)">Save</button>//模板对象
<button *ngFor="let hero of heroes" (click)="deleteHero(hero)">{{hero.name}}</button>//模板输入变量
<form #heroForm (ngSubmit)="onSubmit(heroForm)"> ... </form>//模板引用变量
Class设置
<div [class.special]="isSpecial">Special</div>
或者[class]="isSpecial"
或者
<div [ngClass]="currentClasses">This div is initially saveable</div>
其中currentClasses是一个对象,每个key都是类名,value是布尔值
<button [style.color]="isSpecial ? 'red' : 'green'">
或者
<div [ngStyle]="currentStyles">This div is initially italic</div>
其中currentStyles是一个对象,
this.currentStyles = {
'font-style': this.canSave ? 'italic' : 'normal',
'font-weight': !this.isUnchanged ? 'bold' : 'normal',
'font-size': this.isSpecial ? '24px' : '12px'
};
[()]都是双向绑定,而[(ngModel)]依赖[FormsModule]
ngIf指令通常会用来防范空指针错误。
ngSwitch
<div [ngSwitch]="currentHero.emotion">
<happy-hero *ngSwitchCase="'happy'" [hero]="currentHero"></happy-hero>
<sad-hero *ngSwitchCase="'sad'" [hero]="currentHero"></sad-hero>
<confused-hero *ngSwitchCase="'confused'" [hero]="currentHero"></confused-hero>
<unknown-hero *ngSwitchDefault [hero]="currentHero"></unknown-hero>
</div>
引用变量
<input #phone placeholder="phone number">或者
<input ref-phone placeholder="phone number">
<button (click)="callPhone(phone.value)">Call</button>
模板引用变量的作用范围是整个模板。 不要在同一个模板中多次定义同一个变量名,否则它在运行期间的值是无法确定的。
输入和输出属性
@Input() hero: Hero;
@Output() deleteRequest = new EventEmitter<Hero>();
或者
@Component({
inputs: ['hero'],
outputs: ['deleteRequest'],
})
指定别名
@Output('myClick') clicks = new EventEmitter<string>();
或者
@Directive({
outputs: ['clicks:myClick'] // propertyName:alias
})
管道操作符
类似过滤器
将obj渲染在页面:
<div>{{currentHero | json}}</div>
安全导航操作符( ?. )
{{name}}如果name不存在,则仅仅不渲染
但是{{hero.name}}的hero如果不存在,则直接报错,因此可以采用NgIf环绕保护,或直接
生命周期钩子函数
OnInit()钩子:
在构造函数之后马上执行复杂的初始化逻辑
OnChanges() 钩子:
一旦检测到该组件(或指令)的输入属性发生了变化,Angular就会调用它的ngOnChanges()方法。
每个组件的css只对自身生效
:host为宿主元素伪类选择器,可以选中该组件的宿主元素
指定的styleUrlsURL是相对于应用程序根目录的,它通常是应用的宿主页面index.html所在的地方。
Angular的<ng-container>是一个分组元素,但它不会污染样式或元素布局,因为 Angular 压根不会把它放进 DOM 中。
一般配合*ngFor使用,给其提供一个宿主
$event.target即事件对象元素自身
<input #box (keyup)="0">
<p>{{box.value}}</p>
只有在应用做了些异步事件(如击键),Angular 才更新绑定(并最终影响到屏幕)。将keyup事件绑定到了数字0,这是可能是最短的模板语句。 虽然这个语句不做什么,但它满足 Angular 的要求,所以 Angular 将更新屏幕。
事件(keyup.enter)只关注回车键事件
(blur)事件
<form #heroForm="ngForm">
Angular会在<form>标签上自动创建并附加一个[NgForm]指令。
此时每个input元素都应该有唯一的name属性,否则报错
NgModel 指令不仅仅跟踪状态。它还使用特定的 Angular CSS 类来更新控件,以反映当前状态:
控件被访问过。
ng-touched ng-untouched
控件的值变化了。
ng-dirty ng-pristine
控件的值有效。
ng-valid ng-invalid
<button type="button" class="btn btn-default" (click)="newHero(); heroForm.reset()">New Hero</button>
.reset()方法重置表单.使各状态重置且清空表单内容,尤其是变成ng-pristine
<button type="submit" class="btn btn-success" [disabled]="!heroForm.form.valid">Submit</button>
<input id="name" class="form-control"
formControlName="name" required >
<div *ngIf="name.invalid && (name.dirty || name.touched)"
class="alert alert-danger">
<div *ngIf="name.errors.required">
Name is required.
</div>
<div *ngIf="name.errors.minlength">
Name must be at least 4 characters long.
</div>
<div *ngIf="name.errors.forbiddenName">
Name cannot be Bob.
</div>
</div>
不要将 Angular 模块的imports数组与文件顶部的import语句弄混淆了。它们的功能不同。
JavaScript 的import声明允许你访问在其他文件中导出的符号,这样你可以在当前文件引用它们。 我们会往几乎所有类型的应用中加入import语句。 它们与 Angular 毫无关系,Angular 对它们也一无所知。
模块的imports数组是@NgModule元数据中独有的。它告诉 Angular 特定 Angular 模块的信息 — 用@NgModule装饰的类 — 应用需要它们来正常工作。
Angular 模块把组件、指令和管道打包成内聚的功能块,每个模块聚焦于一个特性区域、业务领域、工作流或通用工具。
每个运行在浏览器中的应用都必须导入[BrowserModule],他注册了一些关键的应用服务提供商。 它还包括了一些通用的指令,例如[NgIf]和[NgFor],所以这些指令在该模块的任何组件模板中都是可用的。
启动模块为根模块,自定义的其他模块叫特性模块。