AngularJS学习之四(分支之二):架构概述

架构概述

Angular是一个用于在HTML以及JavaScript或类似于编译为JavaScript的TypeScript语言中构建客户端应用程序的框架。


框架由几个库组成,其中一些是核心的,一些是可选的。

你通过编写HTML模板(带有Angular化的标签),编写组件类来管理这些模板,在services中添加应用程序逻辑,并在模块中组装组件和services。

然后,通过引导程序 root module来启动程序。Angular接管,在浏览器中显示您的应用内容,并根据您提供的指示响应用户的互动。

当然,这里有比已经提到的更多的内容。您将在随后的页面中了解那些详细信息。现在,我们先来关注大局。

overview

这张架构图标识了Angular应用程序的八个主要的构建块:

学习这些构建块,你正在正确的方向前进。

页面引用的代码都有一个可用的live example

模块

Component

Angular应用程序是模块化的,Angular有一个名为Angular modules或NgModules的模块化系统。

Angular模块是一个大问题。本页介绍模块;在Angular modules页会深度地讲解它们。

每个Angular app具有至少一个Angular模块类,theroot module,传统命名为AppModule

虽然root module可以是一个小应用程序的唯一模块,大多数应用程序有更多的功能模块,每个内聚的代码块(模块)专注于一个应用领域,一个工作流,或者是密切相关的功能集。

一个Angular模块,无论是根还是功能,都是一个带着@NgModule装饰器的类。

装饰器是修改JavaScript类的函数。Angular有许多装饰器将元数据附加到类上,以便知道这些类的含义和它们应该如何工作。在Learn more(了解更多)可以了解更多在网络上的装饰器的介绍。

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

  • declarations(装饰品)- 属于这个模块的视图类。Angular有三种视图类:组件指令管道

  • exports-declarations(声明)的子集,在其他模块的组件模板中应该可见和可用。

  • imports-其他模块,需要导出类,被本模块的组件模板声明。

  • providers-本模块services的提供者提供给全局services集合;它们在应用程序的所有部分都可访问。

  • bootstrap-主要应用视图,称为根组件,承载所有其他应用视图。只有root module应设置这个bootstrap属性

这里有一个简单的根模块:

app/app.module.ts

import { NgModule} from '@angular/core';BrowserModule '@angular/platform-browser' @NgModule({ imports:[], providersLogger declarationsAppComponent exports bootstrap]})exportclassAppModule}

AppComponent(怀疑这里写错了,应该是AppModule)的export只是说明如何导出;在该示例中实际上不是必需的。一个root module没有理由export任何东西,因为其他组件不需要导入root module。

通过引导它的root module来运行一个应用程序。在开发过程中,你可能会像这样的main.ts 文件中引导AppModule。

app/main.ts

 platformBrowserDynamic  '@angular/platform-browser-dynamic' './app.module' platformBrowserDynamic().bootstrapModule(AppModule);

Angular 模块和JavaScript模块

Angular模块-一个装饰着@NgModule的类-是Angular的基本特征。

JavaScript还有自己的模块系统,用于管理JavaScript对象的集合。它完全不同,与Angular模块系统无关。

在JavaScript每个文件是一个模块,并在该文件中定义的所有对象属于该模块。该模块声明某些对象是通过export关键词而公共化。其他JavaScript模块使用import语句从其他模块访问公共对象。

 './app.component';
}

可以在网上去学习更多有关JavaScript的模块系统的知识。

这是两个不同和互补的模块系统。同时使用它们来编写您的应用程序。

Angular 库


Component

Angular作为JavaScript模块的一个集合。(这里有些歧义,原本是Angular ships as a collection of JavaScript modules,ships as在这个地方应该如何理解呢?这么翻译,显得和上文不连贯)。你可以把它们理解成为一个库模块。

每一个Angular的库的名字都是以@angular这样的前缀开始的。

您可以用npm包管理器去安装它们,并且用JavaScript的import语句引入它们。

例如,从@angular/core库中引入AngularComponent 装饰器就像这样:

Component;

您还可以使用JavaScript的import语句,从Angular库导入Angularmodules:

;

在上面这个简单的 root module 例子里面,应用程序模块需要在BrowserModule里面的内容。 为了可以访问,像这样把它增加@NgModule元数据中。

imports 通过这样做,你就可以一起使用Angular和JavaScript的模块系统了。

因为这两个系统共享了“imports”和“exports”这两个词汇,所以很容易把它们搞混。那就先放在那里。随着时间的推移和经验的积累,这个混乱会搞清楚的。

Angular modules页可以学到更多。

组件

Component

一个控制一片屏幕的组件称为视图。

例如,下面的视图是由组件来控制的。

  • 具有导航链接的 app root。
  • 英雄列表。
  • 英雄编辑器。

您定义了一个组件的应用程序逻辑 - 它支持视图-在类内部。这个类和视图通过属性方法的API进行交互。

例如,这个HeroListComponent有一个heroes属性,用来返回它从一个服务中获取一个的英雄的数组。HeroListComponent也有一个selectHero()方法设置selectedHero属性,当用户点击选择从该列表中选择一个英雄。

app/hero-list.component.ts (class)

HeroListComponentimplementsOnInit heroesHero[]; selectedHero constructor(private serviceHeroService) ngOnInit()this.heroes =servicegetHeroes(); selectHero(heroselectedHero  hero}

Angular在用户在应用程序中移动时(浏览时)创建,更新和销毁组件。您的app可以就像上面生命的ngOnInit()那样,通过可选的lifecycle hooks(生命周期的挂钩)在每一个时刻进行响应。

模板

Template


您定义一个组件视图和它相伴随的模板。一个模板是一种HTML形式,告诉Angular如何渲染组件。

一个模板看起来像常规HTML,除了一些差异。下面是针对我们的HeroListComponent的一个模板HeroListComponent:



app/hero-list.component.html

   
   
<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><hero-detail *ngIf="selectedHero" [hero]="selectedHero"></hero-detail>

虽然这个模板使用典型的HTML元素像<h2><p>,它也有一些不同。类似*ngFor,{{hero.name}},107); padding:0px 4px">(click),107); padding:0px 4px">[hero],和<hero-detail>代码,使用的是 Angular'stemplate syntax(Angular 模板语法)。

在模板的最后一行时,这个<hero-detail>标签是表示一个新组件的自定义元件,HeroDetailComponent。

该HeroDetailComponent是一个不同于你一直在看的HeroListComponent的组件。该HeroDetailComponent(代码没有显示)呈现一个特定的英雄的事实,即用户从所呈现的列表HeroListComponent中选择英雄。该HeroDetailComponent是HeroListComponent的孩子。

Metadata


请注意如何<hero-detail>轻松地位于原生的HTML元素中。自定义组件与原生HTML在同一布局中无缝组合。





元数据

元数据告诉 Angular 如何去处理一个类。


Looking back at the code(沿着代码往回看)找到HeroListComponent,你可以看到它仅仅是一个类。看不到任何框架的证据,里面也根本没有“Angular”。

事实上,HeroListComponent真的只是一个类。在你把它告诉Angular之前,它并不是一个组件。

想要告诉AngularHeroListComponent是一个组件,那就给这个类附属上元数据。

在 TypeScript中,你使用一个decorator(装饰器)关键字去附属上元数据。这里有一些关于HeroListComponent的元数据:

app/hero-list.component.ts (Metadata)

@Component moduleIdmoduleid,100)"> selector 'hero-list' templateUrl 'hero-list.component.html'HeroService /* . . . */}

这里有一个@Component装饰器,这会立刻把在它下面的这个类标识成一个组件类。,

这个@Component装饰器采用了一个配置对象,这个对象具有Angular所需要的去创建和表示组件和它的视图的信息。

这里有一些可能的@Component配置选项:

  • moduleId:为模块相关的URL(类似templateUrl),设置基础地址的源 (module.id) 。
  • selector:CSS 选择器告诉Angular去创建和插入一个这个组件的实例到在当前的HMTL中找到一个<hero-list>标签的地方。例如,如果一个app的HTML包含<hero-list></hero-list>,然后Angular在这些标签中间插入一个HeroListComponent视图的实例。

  • templateUrl:这个模块的HTML模板的模块相关的地址,显示在上面。

    providers:为服务提供组件所需要的依赖注入提供者的数组(array ofdependency injection providers)。这是一个办法,能让Angular告诉这个组件构造器需要一个HeroService这样它可以获取英雄的列表去显示

@Component中的元数据告诉Angular哪里去获得你为组件指定的主要的构件块。

模板、元数据、和组件一起描述了一个视图。

应用其它元数据装饰器也可以类似地指导Angular的行为。@Injectable@Input、和@Output是一些最流行的装饰器。


这个架构(原文The architectural takeaway,暂时不确认如何解释) 就是你必须在你的代码增加元数据,这样Angular才知道要做什么。

数据绑定

没有框架,你需要负责将数据值送入HTML控件中,并且把用户地反应变成行为和数据的更新。 手动编写这样的推/拉逻辑是令人乏味的,容易产生错误,是任何有经验的jQuery程序员可以作证的一场噩梦。

Angular支持数据绑定,一种机制用于组件的部分和模板对应部分的协作。给模板HTML增加绑定标签去告诉Angular如何去连接双方。

就像图例所示,有四种格式的数据绑定语法。每一种格式都有一个方向,面向DOM的,从DOM出来的,或者是双方向的。



HeroListComponentexample模板有三种格式:

app/hero-list.component.html (binding)

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

双向数据绑定 是一个重要的第四种格式,使用ngModel指示符,在单一的符号中捆绑着属性和事件绑定。这里有一个从HeroDetailComponent模板里面找到的例子:

app/hero-detail.component.html (ngModel)

在双向绑定中,一个数据属性值使用属性绑定从组件流向输入框。使用事件绑定,用户的变化也反向流回组件,重设属性的最后的值。

Angular 在一次JavaScript 事件循环中处理所有数据绑定,从应用组件树的根直到所有的孩子组件。

数据绑定在一个模板和它的组件之间担任着很重要的交流角色。









指示符

Angular模板是动态的。当Angular渲染它们的时候,它根据指示符的指导来改变DOM。

一个指示符是一个带有一个@Directive装饰器的类。一个组件是一个directive-with-a-template(指示符和一个模板);@Component装饰器实际上是一个@Directive装饰器扩展后,带有面向模板的功能

尽管一个组件技术上是一个指示符,但组件是这样的清晰,位于Angular应用程序的中心,这个结构化的总览还是选择将指示符和组件分开。

两个其它类型的指示符也存在:structuralattribute指示符。

它们尝试去在一个元素标签显示(就像attributes所做),有时是通过名字,但是更常见的是作为一个分配或者绑定的目标。

Structural指示符通过增加、移除和替换在DOM中的元素来改变布局。

这个example template使用了两个内建的structural指示符:

app/hero-list.component.html (structural)

 *ngFor="let hero of heroes"></li> *ngIf></hero-detail>
  • *ngFor告诉Angular为每一个在heroes列表中的英雄生成一个<li>
  • *ngIf包含了HeroDetail组件,仅当一个选择的英雄存在的时候。

Attribute指示符修改了一个存在的元素的显示或者表现。在模板中,他们看起来像规则的HTML属性,所有有这样的名字。

ngModel指示符,实现了双向数据绑定,是一个attribute指示符的例子。ngModel通过设置它的显示属性和对于变化事件的响应,修改了一个已经存在元素的表现 (典型的例如<input>) 。

app/hero-detail.component.html (ngModel)

Angular还有一些指示符或者改变了布局结构 (例如,ngSwitch) 或者修改了DOM元素或组件的一些方面(例如,ngStylengClass).

当然,你也可以编写你自己的指示符。类似HeroListComponent的组件就是一种自定义指示符。

服务

服务是一个广阔的分类,包含了任意的值,函数,或者你的应用需要的功能

几乎所有事物都可以是一个服务。一个服务典型上是一个类,带着一个狭窄的定义好的目的。它将做指定的事情并且把它做好。


例子包括

  • 日志服务
  • 数据服务
  • 消息总线
  • 税收计算器
  • 应用程序配置

Angular关于服务没有什么特别的内容。Angular没有关于服务的定义。没有服务基础类,没有地方去注册服务。

但是服务是任何Angular程序的基础。组件是服务的大的消费者。

这里有一个关于服务的类的例子,输出日志到浏览器控制台:

app/logger.service.ts (class)

 logmsg any consolelog); errorerror warnwarn}

HeroService获取英雄并且把他们返回到一个解析了的Promise。这个HeroService依赖这个Logger服务,同时另外一个BackendService处理着服务器通信的工作。

app/hero.service.ts (class)

在组件层面注册意味着你用那个组件的每一个新实例去获取一个新的服务的实例。

关于依赖注入需要记住的点:

  • 依赖注入是装配到Angular结构上的,可以在任何地方使用。

  • 这个注射器是主要的装置。

    • 一个注射器维护者一个它创建的服务实例的容器。
    • 一个注射器可以通过provider创建新的服务实例。
  • 一个提供者是创建服务的秘诀。

  • 使用注射器去注册提供者

总结

你已经学到了Angular应用的八个主要构件块的基础了。

    Dependency injection

那是在Angular应用中的任何东西的基础,从这里起步应该是绰绰有余了。(注:原文是and it's more than enough to get going. )但是它不包括所有你需要知道的。

这里有一个简要的,字母排序的,重要的Angular功能和服务的列表。它们中的大多数会在本套文档中覆盖(或者即将是)。

Animations(动画):不需要对动画技术或CSS的深度掌握的,使用Angualr动画库开发动画组件行为。

Change detection(变更检测):变更检测文档会覆盖Angular是如何确定一个组件的属性值发生了改变,什么时候去更新屏幕,并且它是如何使用zones去插入异步活动和运行它的变更检测策略。

Events(事件):事件文档将会覆盖如何使用组件和服务去触发事件去发布事件或者订阅事件。(注:原文是The events documentation will cover how to use components and services to raise events with mechanisms for publishing and subscribing to events.)

Forms(表单):使用基于HTML验证和脏检查来支持复杂数据场景。

HTTP:用HTTP客户端来和一个服务器进行通信去获取数据,保存数据,调用服务端行为。

Lifecycle hooks(生命周期钩子):通过实现生命周期钩子接口,在一个组件的生命周期的关键时刻嵌入,从构建到销毁。

Pipes(管道):在模板中使用管道去提升用户体验,把值转换成一种显示。考虑这个currency管道表达式:

price | currency:'USD':true

它把42.33的价格显示$42.33

Router(路由器):在客户端程序中的页面间导航,并且绝不会离开浏览器。

Testing(测试):使用Angular Testing Platform在你的应用部分运行单元测试,就像它们在与Angular结构交互。

相关文章

AngularJS 是一个JavaScript 框架。它可通过 注:建议把脚本放在 元素的底部。这会提高网页加载速度,因...
angluarjs中页面初始化的时候会出现语法{{}}在页面中问题,也即是页面闪烁问题。出现这个的原因是:由于...
AngularJS 通过被称为指令的新属性来扩展 HTML。AngularJS 指令AngularJS 指令是扩展的 HTML 属性,带有...
AngularJS 使用表达式把数据绑定到 HTML。AngularJS 表达式AngularJS 表达式写在双大括号内:{{ expres...
ng-repeat 指令可以完美的显示表格。在表格中显示数据 {{ x.Name }} {{ x.Country }} 使用 CSS 样式为了...
$http是 AngularJS 中的一个核心服务,用于读取远程服务器的数据。读取 JSON 文件下是存储在web服务器上...