首页 > 代码库 > angular2自学笔记(二)---八大主要构造块

angular2自学笔记(二)---八大主要构造块

angular的思想:总是把数据访问工作委托给一个支持性服务类。

Angular 应用的:用 Angular 扩展语法编写 HTML 模板, 用组件类管理这些模板,用服务添加应用逻辑, 用模块打包发布组件与服务。

我们通过引导根模块来启动该应用。 Angular 在浏览器中接管、展现应用的内容,并根据我们提供的操作指令响应用户的交互。

angular2的八大主要构造块:
模块 (module)
组件 (component)
模板 (template)
元数据 (metadata)
数据绑定 (data binding)
指令 (directive)
服务 (service)
依赖注入 (dependency injection)

一。模块
Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules。
每个 Angular 应用至少有一个模块(根模块),习惯上命名为AppModule。
根模块在一些小型应用中可能是唯一的模块,大多数应用会有很多特性模块,每个模块都是一个内聚的代码块专注于某个应用领域、工作流或紧密相关的功能。
Angular 模块(无论是根模块还是特性模块)都是一个带有@NgModule装饰器的类。
装饰器是用来修饰 JavaScript 类的函数。 Angular 有很多装饰器,它们负责把元数据附加到类上,以了解那些类的设计意图以及它们应如何工作。


NgModule是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:

官网解释:
imports - 本模块声明的组件模板需要的类所在的其它模块。
declarations - 声明本模块中拥有的视图类。 Angular 有三种视图类:组件、指令和管道。
exports - declarations 的子集,可用于其它模块的组件模板。
providers - 服务的创建者,并加入到全局服务列表中,可用于应用任何部分。
bootstrap - 指定应用的主视图(称为根组件),它是所有其它视图的宿主。只有根模块才能设置bootstrap属性。

理解:
imports:导入其他模块,就是要使用其他模块的功能,必须要导入。
declarations:声明,声明本模块包含的内容。可能有些同学会遇到,定义了一个指令,在component中使用却总是没有生效的问题,首先我们要检查的就是是否进行了声明。
exports:外部可见的内容。相当于.net中声明为public的那些类。
providers:服务提供者,主要用来定义服务。估计ng2框架会自动将注册的服务体检到依赖注入实例中,目前测试也是如此。
bootstrap:启动模块。只在根模块使用。在除了根模块以外的其他模块不能使用。


eg:

import { NgModule }      from @angular/core;
import { BrowserModule } from @angular/platform-browser;
@NgModule({
  imports:      [ BrowserModule ],
  providers:    [ Logger ],
  declarations: [ AppComponent ],
  exports:      [ AppComponent ],
  bootstrap:    [ AppComponent ]
})
export class AppModule { }

AppComponent的export语句只是用于演示如何导出的,它在这个例子中并不是必须的。根模块不需要导出任何东西,因为其它组件不需要导入根模块。


Angular 模块 vs. JavaScript 模块
JavaScript 也有自己的模块系统,用来管理一组 JavaScript 对象。 它与 Angular 的模块系统完全不同且完全无关。
JavaScript 中,每个文件是一个模块,文件中定义的所有对象都从属于那个模块。 通过export关键字,模块可以把它的某些对象声明为公共的。 其它 JavaScript 模块可以使用import 语句来访问这些公共对象。

引入:import {javascript模块名} from ‘文件相对路径‘;  
        使用装饰器之前需要从angular2的库中引入装饰器组件    import  {Component} from ‘@angular/core‘;
        从angular中导入angular模块: import {BrowserModule} from ‘@angular/platform-browser‘;

        两个系统比较容易混淆,共享相同的词汇 “imports” 和 “exports”。

定义:export class 模块名 { javascript代码块 }


二.组件
组件负责控制屏幕上的一小块区域,我们称之为视图。

**组件在类中定义组件的应用逻辑,为视图提供支持。 组件通过一些由属性和方法组成的 API 与视图交互。

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; }
}

生命周期钩子:当用户在这个应用中漫游时,Angular会创建、更新和销毁组件。在组件生命周期的各个时间点上插入自己的操作,例如上面声明的ngOnInit()。生命钩子也需要提前引入import { OnInit } from ‘@angular/core‘;


 三.模板

     模板中可以任意使用自定义组件和原生HTML、模板语法(*ngFor、{{hero.name}}、(click)、[hero]);



四.元数据:元数据告诉 Angular 如何处理一个类

上边的组件HeroListComponent其实就是一个类,想要把类变为组件,需要把元数据添加到这个类,在TypeScript 中,我们用装饰器 (decorator) 来附加元数据。

@Component({
  moduleId: module.id,
  selector:    hero-list,
  templateUrl: hero-list.component.html,
  providers:  [ HeroService ]
})
export class HeroListComponent implements OnInit {
  /* . . . */
}

@Component装饰器能接受一个配置对象, Angular 会基于这些信息创建和展示组件及其视图。

 @Component的配置项包括:
    moduleId: 为与模块相关的 URL(例如templateUrl)提供基地址。
    selector: CSS 选择器,它告诉 Angular 在父级 HTML 中查找<hero-list>标签,创建并插入该组件。 例如,如果应用的 HTML 包含<hero-list></hero-list>, Angular 就会把HeroListComponent的一个实例插入到这个标签中。
    templateUrl:组件 HTML 模板的模块相对地址,如前所示。
    providers:组件所需服务的依赖注入提供商数组,Angular:该组件的构造函数需要一个HeroService服务,这样组件就可以从服务中获得英雄数据。

@Component里面的元数据会告诉 Angular 从哪里获取你为组件指定的主要的构建块。模板、元数据和组件共同描绘出这个视图。
其它元数据装饰器用类似的方式来指导 Angular 的行为。 例如@Injectable、@Input和@Output等是一些最常用的装饰器。这种架构处理方式是:你向代码中添加元数据,以便 Angular 知道该怎么做。


五.数据绑定

    数据绑定的语法有四种形式。
    绑定到DOM:  [prototype]="value";    (even)="handle"    
    绑定到DOM:  {{vlue}}
    双向绑定:   [(ng-module)]="property";

    eg:
    {{hero.name}}插值表达式在<li>标签中显示组件的hero.name属性的值。
    [hero]属性绑定把父组件HeroListComponent的selectedHero的值传到子组件HeroDetailComponent的hero属性中。
    (click) 事件绑定在用户点击英雄的名字时调用组件的selectHero方法。
    <input [(ngModel)]="hero.name"> 双向数据绑定:数据属性值通过属性绑定从组件流到输入框。用户的修改通过事件绑定流回组件,把属性值设置为最新的值

    Angular 在每个 JavaScript 事件循环中处理所有的数据绑定,它会从组件树的根部开始,递归处理全部子组件。


六.指令:Angular 模板是动态的。当 Angular 渲染它们时,它会根据指令提供的操作对 DOM 进行转换。

指令和模板的区别:
指令是一个带有“指令元数据”的类。在 TypeScript 中,要通过@Directive装饰器把元数据附加到类上。组件是一个带模板的指令;@Component装饰器实际上就是一个@Directive装饰器,只是扩展了一些面向模板的特性。

还有两种其它类型的指令:结构型指令和属性 (attribute) 型指令。
        1.结构型指令:通过在 DOM 中添加、移除和替换元素来修改布局。
            <li *ngFor="let hero of heroes"></li>
            <hero-detail *ngIf="selectedHero"></hero-detail>

        2.属性型指令:修改一个现有元素的外观或行为。 在模板中,它们看起来就像是标准的 HTML 属性。
            ngModel指令就是属性型指令的一个例子,它实现了双向数据绑定。 ngModel修改现有元素(一般是<input>)的行为:设置其显示属性值,并响应 change 事件。
            <input [(ngModel)]="hero.name">

        3.自定义指令:如上面的HeroListComponent就是一个自定义指令


七.服务:

    一个把记录到console.log的服务类示例:

export class Logger {
          log(msg: any)   { console.log(msg); }
          error(msg: any) { console.error(msg); }
          warn(msg: any)  { console.warn(msg); }
        }

通过向后台传递数据并通过一个已接收的promise返回数据:

export class HeroService {
          private heroes: Hero[] = [];

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

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

服务的getHeroes()和addHero()方法返回一个英雄数据的可观察对象Observable这些数据是由AngularHttp从服务器上获取的。我们可以把可观察对象Observable看做一个由某些“源”发布的事件流。 通过订阅到可观察对象Observable,我们监听这个流中的事件。 在这些订阅中,我们指定了当 Web 请求生成了一个成功事件(有效载荷是英雄数据) 或失败事件(有效载荷是错误对象)时该如何采取行动。

    组件本身不从服务器获得数据、不进行验证输入,也不直接往控制台写日志。 它们把这些任务委托给服务。
    组件的任务就是提供用户体验。它介于视图(由模板渲染)和应用逻辑(通常包括模型的某些概念)之间。设计良好的组件为数据绑定提供属性和方法,把其它琐事都委托给服务。把应用逻辑拆分到服务,并通过依赖注入来在组件中使用这些服务。

八.依赖注入:
    “依赖注入”是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。Angular使用依赖注入来提供新组件以及组件所需的服务。
    Angular 通过查看构造函数的参数类型得知组件需要哪些服务。 例如,HeroListComponent组件的构造函数需要一个HeroService服务:
        constructor(private service: HeroService) { }
    当 Angular 创建组件时,会首先为组件所需的服务请求一个注入器 (injector)。

    依赖注入的流程:
        注入器维护了一个服务实例的容器,存放着以前创建的实例。如果所请求的服务实例不在容器中,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给Angular。当所有请求的服务都被解析完并返回时,Angular会以这些服务为参数去调用组件的构造函数。

    在要求注入HeroService之前,在注入器中注册HeroService的提供商 Provider。 提供商用于创建并返回一个服务,通常是服务类本身。
我们可以在模块或组件中注册提供商。通常会把提供商添加到根模块上,以便在任何地方使用服务的同一个实例。

providers: [
          BackendService,
          HeroService,
          Logger
        ],

也可以在@Component元数据中的providers属性中把它注册在组件层,表示该组件的每一个新实例都会有一个服务的新实例。

@Component({
          moduleId: module.id,
          selector:    hero-list,
          templateUrl: hero-list.component.html,
          providers:  [ HeroService ]
        })

需要记住的关于依赖注入的要点是:
        依赖注入渗透在整个 Angular 框架中,被到处使用。
        注入器 (injector) 是本机制的核心。
        注入器负责维护一个容器,用于存放它创建过的服务实例。
        注入器能使用提供商创建一个新的服务实例。
        提供商是一个用于创建服务的配方。
        把提供商注册到注入器。

angular2自学笔记(二)---八大主要构造块