Angular 2 应用主要由以下 几个部分组成:
1、模块 (Modules):
2、组件 (Components):
3、模板 (Templates):
4、元数据 (Metadata):
5、数据绑定 (Data Binding)
6、指令 (Directives)
7、服务 (Services):
8、依赖注入 (Dependency Injection)
9、路由(Route):建立URL路径和组件之间的对应关系,根据不同的URL路径匹配对应的组件并渲染。
元数据就是在定义模块、组件、服务的时候,Decorator(装饰器)方法里面的参数内容,例如一个AppComponent的元数据,就是 @Component 里面的参数,如下:
{
selector : 'mylist',
template : '元数据
'
directives : [ComponentDetails]
}
在Angular2中,Decorator(装饰器)被大量使用,当我们定义模板、组件、服务、指令时,都是使用Decorator来定义。顾名思义,Decorator(装饰器)就是在一个类上面添加一些额外的属性或方法。
举个例子,根组件AppComponent,在定义它的时候,通过 @Component 才能把它定义成一个Angular的组件。然后我们在这个元数据里面,设置了这个组件对应的selector,模板和样式。
这样Angular框架在解析这个类的时候,就会按照组件的规则去解析并初始化。
当在一个页面里面遇到这个selector设置的标签时,就会初始化这个组件,渲染模板生成html显示到对应的标签里面,并应用样式。
module是指使用@NgModule修饰的class。
@NgModule利用一个元数据对象来告诉Angular如何去编译和运行代码。
可以将组件、服务、指令、方法、管道等封装成一个模块,并且可以将它们的访问权限声明为公有,以便外部模块的组件可以访问和使用到它们。
Angular2将许多常用功能分配到一个个的模块中:
在使用前,需导入相关模块包:
Angular 模块是一个带有 @NgModule 装饰器的类,它接收一个用来描述模块属性的元数据对象。
一个最简单的根模块:
//app/app.module.ts 文件:
import { NgModule } from '@angular/core'; //从 @angular/core 中引入 NgModule 修饰器
import { BrowserModule } from '@angular/platform-browser';
@NgModule({
imports: [ BrowserModule ],
providers: [ Logger ],
declarations: [ AppComponent ],
exports: [ AppComponent ],
bootstrap: [ AppComponent ]
})
export class AppModule { }//定义根模块
组件是构成Angular2应用的砖块。
包括三个部分:带有 @Component()
装饰器的 TypeScript 类、HTML 模板和样式文件。
一个简单的组件:
import { Component } from '@angular/core';//从 @angular/core 中引入 NgModule 修饰器
@Component({
selector: 'hello-world',
template: `
Hello World
This is my first component!
`
})
export class HelloWorldComponent {
//在此类中的代码驱动组件的行为。
}
在html中使用此组件:
在一个Angular2的应用中,组件是一个属性结构,就好像html的DOM树一样,每个Angular2应用都有一个根组件,然后它会有一个个的子组件。得到的是一个组件树。每个组件(除了根组件)都有一个父组件,每个组件定义中“selector”的值,对应父组件中的一个html标签。
在Angular中,有多种方法可以实现父子组件通信。
以下是几种常用的方法:
输入属性是一种用于从父组件向子组件传递数据的方法。通过使用@Input()装饰器,我们可以在子组件中定义一个公共属性来接收来自父组件的数据。
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-child',
template: '{{ message }}
'
})
export class ChildComponent {
@Input() message: string;
}
在上述代码中,我们使用@Input()装饰器来定义了一个名为message的输入属性。在子组件的模板中,我们使用插值表达式{{ message }}
来展示接收到的消息。
输出属性允许子组件向父组件传递信息。通过使用事件触发器和@Output()装饰器,我们可以在子组件中定义一个事件,并在适当的时候将数据作为事件参数发送给父组件。
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-child',
template: ''
})
export class ChildComponent {
@Output() messageEvent = new EventEmitter();
sendMessage() {
this.messageEvent.emit('Hello from child component');
}
}
在上述代码中,我们定义了一个名为messageEvent的输出属性,并使用EventEmitter来创建一个新的事件。在子组件中,当用户点击按钮时,我们通过调用sendMessage()方法并使用emit()方法来触发messageEvent事件,并将一个字符串作为参数传递给父组件。
服务是一种共享数据和状态的有效方式。通过创建一个共享的服务,我们可以在任何组件之间传递数据和共享状态。组件可以通过依赖注入服务,并使用服务提供的方法和属性进行通信。
import { Injectable } from '@angular/core';
@Injectable()
export class DataService {
private message: string;
setMessage(message: string) {
this.message = message;
}
getMessage() {
return this.message;
}
}
在上述代码中,我们创建了一个名为DataService的服务,并在其中定义了一个私有的message属性和相应的设置和获取方法。通过在需要访问该数据的组件中注入DataService,我们可以在组件之间共享数据。
通过使用ViewChild和ContentChild装饰器,我们可以在父组件中获取对子组件的引用,并直接调用子组件的方法或访问其属性。这种方法适用于需要直接与子组件进行交互的情况。
import { Component, ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';
@Component({
selector: 'app-parent',
template: `
`
})
export class ParentComponent {
@ViewChild(ChildComponent) childComponent: ChildComponent;
callChildMethod() {
this.childComponent.childMethod();
}
}
在上述代码中,我们使用@ViewChild()装饰器来获取对ChildComponent的引用,并将其赋值给childComponent属性。然后,在父组件的模板中,我们使用一个按钮来触发callChildMethod()方法,该方法会调用子组件中的childMethod()方法。
Angular2的数据更新检测是在每个组件上有一个检测器。这样,就算应用中有再多绑定的变量,当有一个数据修改后,也只是对应的那个组件的检测器被触发,来检查它以及它所有的子组件的数据修改。
Angular 添加了一些语法元素以扩展 HTML,让你可以从组件中插入动态值。当组件的状态更改时,Angular 会自动更新已渲染的 DOM。
数据绑定的语法有四种形式:
1、插值 {{}} : 在 HTML 标签中显示组件值。(单向)
{{title}}
2、属性绑定 []: 把元素的属性设置为组件中属性的值。(单向)
3、事件绑定 (): 通过在圆括号中指定事件名称来声明一个事件监听器(单向)
//在组件方法名被点击时触发
//组件类中定义的方法:
sayMessage() {
alert(this.message);
}
4、双向绑定 [] (): 使用Angular里的NgModel指令可以更便捷的进行双向绑定。
双向绑定就是用户在页面上修改这个值时,这个值就会直接反馈到组件中。同样,如果在组件中通过某种方式修改了这个值,页面上,也会显示最新的值。
对于上面的 [] 和 () 两种类型的绑定,可以理解成’输入’和’输出’。
Angular2并没有对服务的定义做任何的规则限制,任何的类都可以被定义成服务,这个类中可以包含业务方法,也可以包含环境配置变量。
一个简单的服务:
export class loggerServices {
log(msg: any) { console.log(msg); }
error(msg: any) { console.error(msg); }
warn(msg: any) { console.warn(msg); }
}
我们只需要定义一个class,并把它export就可以了。
Angular借用了java等语言中某些容器库的概念,它将所有service实例的创建都由容器来完成。当一个service需要引用另一个service的时候,不需要先创建service实例,然后通过实例调用它的方法或属性,而是直接从容器中获取相应service的实例,无需我们操心如何实例化它们。
在Angular2中,依赖注入 (Dependency Injection) 主要是用于管理service实例的注入。
使用 @Injectable
装饰器以声明此类可以被注入。
@Injectable
export class HeroService {
...
}
然后就可以在其它地方注入并使用它。
在组件级别,使用 @Component
装饰器的 providers字段。在这种情况下,HeroService将可用于此组件的所有实例,以及它的模板中使用的其他组件和指令。也就是说,在当前节点,以及它所有的子节点的组件上,HeroService类的实例是共用的,它们都共享一个服务实例。例如:
@Component({
selector: '...',
template: '...',
providers: [HeroService]
})
class HeroListComponent {}
在 NgModule 级别,要使用 @NgModule
装饰器的 providers字段。在这种情况下,HeroService可用于此 NgModule ,或与本模块位于同一个 ModuleInjector 的其它模块中声明的所有组件、指令和管道。当你向特定的 NgModule 注册提供者时,同一个服务实例可用于该 NgModule 中的所有组件、指令和管道。要理解所有边缘情况,参见多级注入器。例如:
@NgModule({
declarations: [...]
providers: [HeroService]
})
class HeroListModule {}
在应用根级别,允许将其注入应用的其他类中。这可以通过将 providedIn: 'root'字段添加到 @Injectable
装饰器来实现:
@Injectable({
providedIn: 'root'
})
class HeroService {}
当你在根级别提供服务时,Angular 会创建一个 HeroService
的共享实例,并将其注入到任何需要它的类中。在 @Injectable
元数据中注册提供者还允许 Angular 通过从已编译的应用程序中删除没用到的服务来优化应用程序,这个过程称为摇树优化(tree-shaking)。
最常见方法是在类的构造函数中声明它。当 Angular 创建组件、指令或管道类的新实例时,它会通过查看构造函数的参数类型来确定该类需要哪些服务或其他依赖项。例如,如果 HeroListComponent 要用 HeroService,则构造函数可以如下所示:
@Component({ … })
class HeroListComponent {
constructor(private service: HeroService) {}
}