我爱编程

Angular2 ARCHITECTURE OVERVIEW学习

2016-05-06  本文已影响167人  escawn

官网地址:https://angular.io/docs/ts/latest/guide/architecture.html

结构图

Angular结构图Angular结构图

结构图囊括了构成一个Angular2应用的八块主要内容

  1. Module
  2. Component
  3. Template
  4. Metadata
  5. Data Binding
  6. Directive
  7. Service
  8. Dependency Injection

Module

Module:模块

Angular应用是模块化的,通常我们的应用是由许多个模块集合而成的。

一个典型的模块,包含着一串只专注于实现一个目的的代码,它会导出这串代码中有价值的东西,最典型的是一个类。

我们之前(在demo2中)见识过了模块导出一个组件类,由此可知组件类也是由模块导出的东西之一。

大部分应用都含有一个<code>AppComponent</code>,通常,我们可以在一个名为<code>app.component.ts</code>的文件中找到它。文件中会有一句这样的声明:

export class AppComponent { }

这个<code>export</code>声明告诉TypeScript,这是一个模块,它拥有一个<code>AppComponent</code>类,这个类是公开的,并且可供应用中其他模块进行调用。

当我们需要对<code>AppComponent</code>进行引用时,像这样将它导入:

import { AppComponent } from './app.component';

<br />

Library Modules

一些模块是另外一个模块的库。

Angular本身集结了许多模块库,他们被放在npm包中。他们的名字以<code>@angular</code>打头。

<code>@angular/core</code>是一种常见的初级模块库,我们所需要的大部分东西都可以从中取得。

还有一些常见的模块库,比如
<code>@angular/common</code>,<code>@angular/router</code>,<code>@angular/http</code>等等。

我们导入库的方法是类似的,比如我们导入Angular<code>Component
</code>函数

import { Component } from '@angular/core';

对比一下之前导入我们自己创建的<code>AppComponent</code>

import { AppComponent } from './app.component';

可以发现,路径名是不同的。

Key
  1. Angular应用是一系列模块构成的。
  2. 模块总会导出一些东西,比如类、函数或者值,然后这些东西被其他的模块所引用。
  3. 我们偏向于将应用写成模块的集合,一个模块导出一样东西(专注于一个目的)。
    <br />

The Component

一个组件控制一个视图。

例如,<code>HeroListComponent</code>,拥有一个<code>heroes</code>属性,这个属性从一个服务中返回一个heroes的数组。它还拥有一个<code>selectHero()</code>方法,这个方法在用户从列表中点击一个hero时,设置一个<code>selectedHero</code>属性。

export class HeroListComponent implements OnInit {
  constructor(private service: HeroService) { }
  heroes: Hero[];
  selectedHero: Hero;
  ngOnInit() {
    this.heroes = this.service.getHeroes();
  }
  selectHero(hero: Hero) { this.selectedHero = hero; }
}

Angular在用户使用应用的时候,创建、更新、销毁组件,开发者可以在这个生命周期的任一时刻采取任何行动。
<br />

The Template

我们在组件中定义template,一个template是HTML的一部分,它告诉Angular如何渲染组件。

一个template大部分与HTML很相似,但也有不同的地方。这是<code>HeroList</code>组件中的template。

<h2>Hero List</h2>
<p><i>Pick a hero from the list</i></p>
<div *ngFor="let hero of heroes" (click)="selectHero(hero)">
  {{hero.name}}
</div>
<hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>

<code><hero-detail></code>标签代表着<code>HeroDetailComponent</code>.

<code>HeroDetailComponent</code>可以说是<code>HeroListComponent</code>的孩子。Root Template中包含Child Component和Child Template,Child Template中又包含GrandChild Component和GrandChild Template.我们可以这样将组件混合起来,利用原生的HTML元素,在同一个页面中进行展示。

我们将组建复杂的组件树,来创建我们功能丰富的应用。
<br />

Angular Metadata

Metadata告诉Angular如何处理一个类。

当我们回过头来看<code>HeroListComponent</code>时,它像一个类,直到我们告诉Angular这是一个组件。我们使用给这个类附上metadata的方式来告诉Angular.

一个简单有效的附带metadata的方法是使用decorator。

@Component({
  selector:    'hero-list',
  templateUrl: 'app/hero-list.component.html',
  directives:  [HeroDetailComponent],
  providers:   [HeroService]
})
export class HeroesComponent { ... }

这里我们使用了<code>@Component</code>decorator.

一个decorator是一个函数。Decorators通常有一个构造参数。<code>@Component</code>decorator包含了一个对象,这个对象携带有Angular需要创建和展示的组件及其视图的全部信息。

接下来我们看看<code>@Component</code>中可能包含的选项。

  1. selector
    css选择器告诉Angular在HTML找到<code><hero-list></code>标签,在标签里创建然后插入这个<code>HeroListComponent</code>的视图。
  2. templateUrl
    组件template所在地址,template是组件要展示出来的视图。
  3. directives
    template所需的Components或者Directives的一个数组。刚才我们提到,template希望Angular在<code><hero-detail></code>标签出现的地方插入<code>HeroDetailComponent</code>,而只有当<code>HeroDetailComponent</code>在<code>directives</code>被提到之后,Angular才会按照我们所期待的那样去做。
  4. providers
    这是一个数组,数组中对组件所需的服务提供了依赖注入。可以使用这个方法来告诉Angular,我们的组件需要<code>HeroService</code>,这样它可以从这个服务中获得英雄列表来展示。

总结:The @Component function takes the configuration object and turns it into metadata that it attaches to the component class definition. Angular discovers this metadata at runtime and thus knows how to do "the right thing".
The template, metadata, and component together describe the view.
<br />

Data Binding

data bindingdata binding

没有框架的帮助时,我们需要将数据push进html,然后获取用户的响应动作,以此来更新数据。这样手动实现push/pull逻辑是很乏味的。

Angular支持data binding,一种使得template和组件其他部分能够相互协作的机制。

data binding语法有四种。这里我们展示了三种。

<div>{{hero.name}}</div>
<hero-detail [hero]="selectedHero"></hero-detail>
<div (click)="selectHero(hero)"></div>

interpolation在<code><div></code>标签中展示了组件的<code>hero.name</code>属性。
property binding 通过<code>[hero]</code>将父组件<code>HeroListComponent</code>的<code>selectedHero</code>,传给了孩子组件<code>HeroDetailComponent</code>的属性<code>hero</code>.
event binding <code>(click)</code>是一个事件绑定,它将在用户点击hero's name时调用<code>selectHero</code>方法。
Two-way data binding通过使用<code>ngModel</code>指令可以实现属性和事件的结合绑定。

<input [(ngModel)]="hero.name">

用户的输入改变同样会回传给组件,造成组件中属性的改变。


template与component bindingtemplate与component binding
parent与child bindingparent与child binding

data binding在template与它的组件的沟通中起到了重大的作用。
<br />

The Directive

templates是动态变化的,当Angular对它进行渲染时,它根据directive给的指示对DOM做出改变。

一个 directive是一个有directive metadata的类。在Typescript中我们使用<code>@Directive</code>decorator来将metadata与类连接。

组件也是directive的一种。<code>@Component</code>decorator是含有template的一种<code>@Directive</code>decorator.

Directives中有两种,我们称之为"structural" 和 "attribute" 的directives.他们通常出现在HTML标签中,就像attributes一样。

Structural directives通过对DOM进行增添、移动、替代操作来展示视图。

<div *ngFor="let hero of heroes"></div>
<hero-detail *ngIf="selectedHero"></hero-detail>

<code>*ngFor</code>告诉Angular用<div>对<code>heroes</code>列表中的每一个hero进行展示。
<code>*ngIf</code>只有当选中的hero存在时,包含<code>HeroDetail</code>.

Attribute directives对存在的元素进行外观或者行为的操作。在template中,它们看起来就像常规的HTML attributes.

<input [(ngModel)]="hero.name">

<code>ngModel</code>改变了已经存在的元素<code><input></code>的行为,设置了它展示出来的属性值,使它对输入改变这个事件作出响应。
<br />

The Service

Service包含着大量我们所需要的函数、值、属性。几乎所有东西都可以成为service。service是一个拥有单一目的的类。举例:
logging service
data service
message bus
tax calculator
application configuration

Angular自身没有关于service的定义,也就是说,并没有一个service的基类。

export class HeroService {
  constructor(
    private backend: BackendService,
    private logger: Logger) { }

  private heroes: Hero[] = [];

  getHeroes() {
    this.backend.getAll(Hero).then( (heroes: Hero[]) => {
      this.logger.log(`Fetched ${heroes.length} heroes.`);
      this.heroes.push(...heroes); // fill cache
    });
    return this.heroes;
  }
}

<code>HeroService</code>依赖于<code>LoggerService</code>和<code> BackendService</code>.它fetch一个hero,并返回它。

组件是service的主要服务对象。它们依赖service去掌控细枝末节。它们将诸如从服务器获取数据、验证用户输入这样的琐事交给service。

Angular使得我们将应用逻辑写入service变得简单,并且通过依赖注入使得service对组件是可用的。
<br />

Dependency Injection

"Dependency Injection"是一种提供类的新实例的方式,它包含了类所需的所有依赖。大部分依赖都是service。Angular给component提供它们所需的service.

constructor(private service: HeroService) { }

当Angular创建一个新的组件时,它首先会向Injector要求组件所需的service。

一个Injector掌控含有预先创建的service实例的容器。如果所需service不在这个容器中,injector会在对Angular响应之前创建一个,并把它加入到容器中。当Angular得到了所有所需的service,将这些service作为参数传入到组件构造器中。

HeroService injectionHeroService injection

当没有<code>HeroService</code>时,如何创建一个service?

简要地说,我们必须有一个事先注册好的<code>HeroService</code>的provider,provider可以创建或者返回service。

我们可以再应用组件树的任何一层注册provider。我们通常在根部完成此事,在我们bootstrap我们的应用时。这样这个service的实例就可以在任何位置被调用了。

bootstrap(AppComponent, [BackendService, HeroService, Logger]);

bootstrap是启动和配置根应用组件的方法。

key
  1. injector掌控一个含有它创建的service实例的容器。
    injector可以利用provider创建一个它没有的service实例。
  2. provider对于创建service来说就像食谱。
  3. 我们通过injector注册provider.
上一篇下一篇

猜你喜欢

热点阅读