Angular从零到一
上QQ阅读APP看书,第一时间看更新

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() {
            }
          }