1.5 一些基础概念
有了前面的例子,就可以粗略介绍一些Angular的基础概念了,这些基础概念在后面的章节中会更详细地讲解。
1.5.1 元数据和装饰器
Angular中大量地使用了元数据。元数据是什么呢?元数据的定义是这样的:元数据是用来描述数据的数据。
天啊,这什么意思啊?没关系,我们来看一个例子,大家都在电脑上有文件浏览器,随便选择一个文件,我们可以右键选择这个文件的属性看一下,如图1.6所示。
图1.6 文件的元数据描述
我们看到文件本身其实就是一个二进制格式的数据,而在文件的属性中我们又发现了对此数据的描述,包括:文件的种类、文件的大小、文件的位置、创建时间、修改时间等通用信息,也发现了如打开方式的描述、权限的描述等信息。这就是文件的元数据。
那么在编程语言的世界中,如何表示这种元数据呢?每种编程语言都有自己的选择,但Angular 2的元数据表示方法和Java、Python等编程语言中的元数据表示法很类似。那就是以@这个符号定义一个对象表示后面的数据是一个元数据,这个元数据一般修饰紧挨着它的那个对象或变量。
比如我们之前改过一段代码,@Component(…)中描述的就是LoginComponent的元数据,这段元数据告诉我们LoginComponent的一些属性,比如它对外部的选择器名称(也就是标签)应该叫做app-login,它的模板是什么样子,样式是什么样子,等等。我们一般管@Component叫做组件的装饰器,它的作用就是表示清楚元数据,代码如下所示:
@Component({ selector: 'app-login', template: ' <p> login Works! </p> ', styles: [] }) export class LoginComponent implements OnInit { constructor() { } ngOnInit() { } }
1.5.2 模块
简单来说,模块就是提供相对独立功能的功能块,每块聚焦于一个特定业务领域。Angular内建的很多库是以模块形式提供的,比如FormsModule封装了表单处理,HttpModule封装了HTTP的处理,等等。
Angular模块是带有@NgModule装饰器函数的类。@NgModule接收一个元数据对象,该对象告诉Angular如何编译和运行模块代码。它指出模块拥有的组件、指令和管道,并把它们的一部分公开出去,以便外部组件使用它们。它可以向应用的依赖注入器中添加服务提供商。(依赖性注入和服务的概念我们在稍后的章节中讲解,此处暂时略过。)
NgModule是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其中最重要的属性是:
❑declarations:声明本模块中拥有的视图类。Angular有三种视图类:组件、指令和管道。
❑exports:declarations的子集,可用于其他模块的组件模板。
❑imports:本模块声明的组件模板需要的类所在的其他模块。
❑providers:服务的创建者,并加入到全局服务列表中,可用于应用任何部分。
❑bootstrap:指定应用的主视图(称为根组件),它是所有其他视图的宿主。只有根模块才能设置bootstrap属性。
每个Angular应用至少有一个模块类——习惯上叫它“根模块”,我们将通过引导根模块来启动应用。根模块在一些小型应用中可能是唯一,但大多数应用会有很多特性模块,每个模块都是一个内聚的代码块专注于某个应用领域、工作流或紧密相关的功能。按照约定,根模块的类名叫做AppModule,放在app.module.ts文件中。我们这个例子中的根模块位于hello-angular\src\app\app.module.ts,代码如下:
import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { HttpModule } from '@angular/http'; import { AppComponent } from './app.component'; import { LoginComponent } from './login/login.component'; @NgModule({ declarations: [ AppComponent, LoginComponent ], imports: [ BrowserModule, FormsModule, HttpModule ], providers: [], bootstrap: [AppComponent] }) export class AppModule { }
@NgModule装饰器用来为模块定义元数据。declarations列出了应用中的顶层组件,包括引导性组件AppComponent和我们刚刚创建的LoginComponent。在module里面声明的组件在module范围内都可以直接使用,也就是说在同一module里面的任何Component都可以在其模板文件中直接使用声明的组件,就像我们在AppComponent的模板末尾加上<app-login></app-login>一样。
imports引入了三个辅助模块:
❑BrowserModule提供了运行在浏览器中的应用所需要的关键服务(Service)和指令(Directive),这个模块对于所有需要在浏览器中跑的应用来说都必须引用。
❑FormsModule提供了表单处理和双向绑定等服务和指令。
❑HttpModule提供HTTP请求和响应的服务。
providers列出会在此模块中“注入”的服务(Service),关于依赖性注入会在后面章节中详细解释。
bootstrap指明哪个组件为引导性组件(本案例中的AppComponent)。当Angular引导应用时,它会在DOM中渲染这个引导性组件,并把结果放进index.html的该组件的元素标签中(本案例中的app-root)。
<! doctype html> <html> <head> <meta charset="utf-8"> <title>HelloAngular</title> <base href="/"> <meta name="viewport" content="width=device-width, initial-scale=1"> <link rel="icon" type="image/x-icon" href="favicon.ico"> </head> <body> <app-root>Loading...</app-root> </body> </html>
1.5.3 组件
组件负责控制屏幕上的一小块区域(称为“视图”,也就是我们的组件模板显示在屏幕上的那块区域)。我们在类中定义组件的应用逻辑,为视图提供支持。组件通过一些由属性和方法组成的API与视图交互。
以我们刚才介绍的组件代码为例,如果我们在LoginComponent中定义一个变量text,在模板中引用这个变量,那么屏幕上组件对应的显示就会变成Hello LoginComponent,这就是一个组件的类是如何与视图进行简单交互的过程:
import { Component, OnInit } from '@angular/core'; //@Component是Angular提供的装饰器函数,用来描述Compoent的元数据 //其中selector是指这个组件的在HTML模板中的标签是什么 //template是嵌入(inline)的HTML模板,如果使用单独文件可用templateUrl //styles是嵌入(inline)的CSS样式,如果使用单独文件可用styleUrls @Component({ selector: 'app-login', template: ' <p> {{text}} </p> ', styles: [] }) export class LoginComponent implements OnInit { text =‘Hello LoginComponent’ constructor() { } ngOnInit() { } }