文章目录
快速上手
搭建环境
- 安装 Angular CLI
npm install -g @angular/cli
- 创建工作空间和初始应用
ng new my-app
- 运行应用
ng serve --open
–open(或者只用 -o 缩写)选项会自动打开你的浏览器,并访问 http://localhost:4200/。
Angular的基本概念
模块
NgModule 为一个组件集声明了编译的上下文环境,它专注于某个应用领域、某个工作流或一组紧密相关的能力。
每个 Angular 应用都有一个根模块,通常命名为 AppModule。根模块提供了用来启动应用的引导机制。 一个应用通常会包含很多特性模块。
组件
@Component() 装饰器表明紧随它的那个类是一个组件,并提供模板和该组件专属的元数据。
服务与依赖注入
对于与特定视图无关并希望跨组件共享的数据或逻辑,可以创建服务类。
类似于Vue中的Vuex
模块简介
每个 Angular 应用都至少有一个 NgModule 类,也就是根模块,它习惯上命名为 AppModule,并位于一个名叫 app.module.ts 的文件中。引导这个根模块就可以启动你的应用。
@NgModule 元数据
重要的属性:
- imports(导入表) —— 那些导出了本模块中的组件模板所需的类的其它模块。
- exports(导出表) —— 那些能在其它模块的组件模板中使用的可声明对象的子集。
- declarations(可声明对象表) —— 那些属于本 NgModule 的组件、指令、管道。
- bootstrap —— 应用的主视图,称为根组件(AppComponent)。它是应用中所有其它视图的宿主。只有根模块才应该设置这个 bootstrap 属性。
- providers —— 本模块向全局服务中贡献的那些服务的创建器。 这些服务能被本应用中的任何部分使用。
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { RouterModule } from '@angular/router';
import { ReactiveFormsModule } from '@angular/forms';
import { AppComponent } from './app.component';
import { TopBarComponent } from './top-bar/top-bar.component';
import { ProductListComponent } from './product-list/product-list.component';
import { ProductAlertsComponent } from './product-alerts/product-alerts.component';
import { ProductDetailsComponent } from './product-details/product-details.component';
import { CartService } from './cart.service';
import { CartComponent } from './cart/cart.component';
import { HttpClientModule } from '@angular/common/http';
import { ShippingComponent } from './shipping/shipping.component';
@NgModule({
imports: [
BrowserModule,
HttpClientModule,
ReactiveFormsModule,
RouterModule.forRoot([
{ path: '', component: ProductListComponent },
{ path: 'products/:productId', component: ProductDetailsComponent },
{ path: 'cart', component: CartComponent },
{ path: 'shipping', component: ShippingComponent },
])
],
declarations: [
AppComponent,
TopBarComponent,
ProductListComponent,
ProductAlertsComponent,
ProductDetailsComponent,
CartComponent,
ShippingComponent
],
bootstrap: [ AppComponent ],
providers: [CartService]
})
export class AppModule { }
Angular 自带的库
每个 Angular 库的名称都带有 @angular 前缀。 使用 npm 包管理器安装 Angular 的库,并使用 JavaScript 的 import 语句导入其中的各个部分。
例如,从 @angular/platform-browser 库中导入 Angular 的 BrowserModule 装饰器:
import { BrowserModule } from '@angular/platform-browser';
应用的根模块需要来自 BrowserModule 中的素材。要访问这些素材,就要把它加入 @NgModule 元数据的 imports 中,代码如下:
imports: [ BrowserModule ],
组件简介
export class HeroListComponent implements OnInit {
heroes: Hero[];
selectedHero: Hero;
constructor(private service: HeroService) { }
ngOnInit() {
this.heroes = this.service.getHeroes();
}
selectHero(hero: Hero) { this.selectedHero = hero; }
}
组件的元数据
可以看到 HeroListComponent 只是一个普通类,完全没有 Angular 特有的标记或语法。 直到给它加上了 @Component 装饰器,它才变成了组件。
组件的元数据告诉 Angular 到哪里获取它需要的主要构造块,以创建和展示这个组件及其视图。 具体来说,它把一个模板(无论是直接内联在代码中还是引用的外部文件)和该组件关联起来。 该组件及其模板,共同描述了一个视图。除了包含或指向模板之外,@Component 的元数据还会配置要如何在 HTML 中引用该组件,以及该组件需要哪些服务等等。
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})
export class HeroListComponent implements OnInit {
/* . . . */
}
最常用的 @Component 配置选项:
- selector:是一个 CSS 选择器。
- templateUrl:该组件的 HTML 模板文件相对于这个组件文件的地址。 另外,你还可以用 template 属性的值来提供内联的 HTML 模板。 这个模板定义了该组件的宿主视图。
- providers:当前组件所需的服务的一个数组。在这个例子中,它告诉 Angular 该如何提供一个 HeroService 实例,以获取要显示的英雄列表。
模板语法
<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<ul>
<li *ngFor="let hero of heroes" (click)="selectHero(hero)">
{{hero.name}}
</li>
</ul>
<app-hero-detail *ngIf="selectedHero" [hero]="selectedHero"></app-hero-detail>
数据绑定
<li>{{hero.name}}</li>
<app-hero-detail [hero]="selectedHero"></app-hero-detail>
<li (click)="selectHero(hero)"></li>
- {{hero.name}} 这个插值在 <li> 标签中显示组件的 hero.name 属性的值。
(与Vue相同)
- [hero]属性绑定把父组件 HeroListComponent 的 selectedHero 的值传到子组件 HeroDetailComponent 的 hero 属性中。
(相当于Vue的v-bind指令)
- 当用户点击某个英雄的名字时,(click) 事件绑定会调用组件的 selectHero 方法。
(相当于Vue的v-on指令)
双向数据绑定:
<input [(ngModel)]="hero.name">
通过 ngModel 指令使用了双向数据绑定(相当于Vue的v-model指令)
管道
带有 @Pipe 装饰器的类中会定义一个转换函数,用来把输入值转换成供视图显示用的输出值。
要在 HTML 模板中指定值的转换方式,请使用 管道操作符 (|)。
{{interpolated_value | pipe_name}}
<!-- Default format: output 'Jun 15, 2015'-->
<p>Today is {{today | date}}</p>
<!-- fullDate format: output 'Monday, June 15, 2015'-->
<p>The date is {{today | date:'fullDate'}}</p>
<!-- shortTime format: output '9:43 AM'-->
<p>The time is {{today | date:'shortTime'}}</p>
指令
指令就是一个带有 @Directive() 装饰器的类。
结构型指令
- *ngFor 是一个迭代器,它要求 Angular 为 heroes 列表中的每个英雄渲染出一个<li>。
- *ngIf 是个条件语句,只有当选中的英雄存在时,它才会包含 HeroDetail 组件。
属性型指令
ngModel 指令就是属性型指令的一个例子,它实现了双向数据绑定。 ngModel 修改现有元素(一般是 <input>)的行为:设置其显示属性值,并响应 change 事件。
服务与依赖注入简介
服务范例
服务也可以依赖其它服务。比如,这里的 HeroService 就依赖于 Logger 服务,它还用 BackendService 来获取英雄数据。BackendService 还可能再转而依赖 HttpClient 服务来从服务器异步获取英雄列表。
依赖注入
在 Angular 中,要把一个类定义为服务,就要用 @Injectable() 装饰器来提供元数据,以便让 Angular 可以把它作为依赖注入到组件中。 同样,也要使用 @Injectable() 装饰器来表明一个组件或其它类(比如另一个服务、管道或 NgModule)拥有一个依赖。
当 Angular 创建组件类的新实例时,它会通过查看该组件类的构造函数,来决定该组件依赖哪些服务或其它依赖项。 比如 HeroListComponent 的构造函数中需要 HeroService:
提供服务
对于要用到的任何服务,你必须至少注册一个提供者。
- 服务可以在自己的元数据中把自己注册为提供者,这样可以让自己随处可用。要注册提供者,就要在服务的 @Injectable() 装饰器中提供它的元数据。
- 你也可以为特定的模块或组件注册提供者。比如在 @NgModule() 或 @Component() 的元数据中。
- 默认情况下,Angular CLI 的 ng generate service 命令会在 @Injectable() 装饰器中提供元数据来把它注册到根注入器中。
@Injectable({
providedIn: 'root',
})
- 当你使用特定的 NgModule 注册提供者时,该服务的同一个实例将会对该 NgModule 中的所有组件可用。要想在这一层注册,请用 @NgModule() 装饰器中的 providers 属性:
@NgModule({
providers: [
BackendService,
Logger
],
...
})
- 当你在组件级注册提供者时,你会为该组件的每一个新实例提供该服务的一个新实例。 要在组件级注册,就要在 @Component() 元数据的 providers 属性中注册服务提供者。
@Component({
selector: 'app-hero-list',
templateUrl: './hero-list.component.html',
providers: [ HeroService ]
})