Angular 学习之路 03 – 模块

上一章我们介绍了 Angular 项目的相关配置文件。这一章我们将简单介绍 Angular CLI 帮我们生成的源代码文件。

main.ts

前面我们说过,src 目录下是全部的源代码文件。首先我们打开 main.ts。main.ts 内容很简单:

import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app/app.module';
import { environment } from './environments/environment';

if (environment.production) {
  enableProdMode();
}

platformBrowserDynamic().bootstrapModule(AppModule)
  .catch(err => console.error(err));

main.ts 是 Angular 项目的入口文件,相当于包含 main() 函数的 C++ 文件或 Java 类文件。这个文件的职责是启动 Angular 模块。我们会在后面详细介绍什么是 Angular 模块,这里只要了解,Angular 应用是由若干模块构成的。模块即构成 Angular 应用的基本单位。main.ts 包含了关于模块以及初始化的语句。

main.ts 的最前面几行import语句是 TypeScript 的语法,表示该 TypeScript 文件需要导入这些模块才可以正确编译。注意,这里导入的模块与前面说的 Angular 模块不是一样的。这里的模块是 JavaScript 模块。例如,

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

即从 Angular 模块 @angular/core 导入enableProdMode函数。

enableProdMode函数用于禁用 Angular 的开发模式,同时开启生产模式。禁用开发模式将会关闭断言等开发时相关的各种检测机制。

platformBrowserDynamic以为着我们要在浏览器启动这个 Angular 应用。这意味着,我们还有其它场合可以启动 Angular 应用,比如服务器端、移动混合端等。

AppModule即该应用的根模块。Angular 最佳实践推荐,每个 Angular 应用都应该有一个名为AppModule模块,这个模块即 Angular 应用的根模块。

environment保存不同的环境变量的值。我们可以在开发模式使用一套环境变量值,在生产模式自动替换为另外的一套变量值,而不需要修改任何代码。

通过上面的介绍,我们大致可以理解 main.ts 的逻辑了:首先判断environment.production是否为true,如果是,则调用enableProdMode()函数;然后通过platformBrowserDynamic()函数启动根模块AppModule

@NgModule

前面说过,每一个 Angular 项目都至少包含一个模块。这个模块一般建议命名为AppModule。事实上,大多数 Angular 项目都会由多于一个的模块构成。Angular 模块可以看作是若干 Angular 元素(组件、指令、管道、服务等)的组合,即 Angular 元素的打包。Angular 元素通过模块的形式可以彼此发现和调用,从而组成一个完整的应用。Angular 使用@NgModule修饰器定义 Angular 模块。

修饰器( decorator )这个术语来自 Python。它与 Java 中的注解(annotation)、C# 中的属性(attribute)类似,用于定义一个类的元数据。

使用@NgModule修饰的类通常也被称为NgModule类。@NgModule需要一个元数据对象。以AppModule模块为例,该对象需要告诉 Angular 如何编译这个模块,以及如何在浏览器启动这个模块。下面是AppModule的代码:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';

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

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

代码开头的几行import语句,前面已经介绍过,这里不再赘述。我们主要来看@NgModule@NgModule修饰器在类AppModule前面,将AppModule类变成一个 Angular 模块。@NgModule接受一个对象,其中,

  1. declarations表示该模块声明了哪些 Angular 元素(可以是组件,也可以是指令、管道等,但不能是服务)。Angular 元素必须被唯一一个模块声明;不允许元素被同时两个模块声明。
  2. imports表示该模块导入了哪些模块。这里的AppModule模块导入了BrowserModule,负责在浏览器运行应用。前面说过,Angular 模块是构成 Angular 应用的最基本单位,其体现之一在于,如果要使用在另外模块声明的元素,必须导入那个模块。也就是说,Angular 元素相互之间以模块为单位相互引用。
  3. providersdeclarations类似,区别在于,providers表示该模块声明了哪些服务。
  4. 在 Angular 应用启动时,根模块AppModule被引导,同时,bootstrap数组中的组件被创建并插入到页面 DOM。虽然bootstrap是一个数组,但绝大多数 Angular 应用都只有一个组件作为启动组件。这个组件会作为整个应用组件树的根,成为 Angular 应用启动之后的第一个组件。

NgModule与 JavaScript(ES2015)模块完全不同。二者是互补的关系,一个 Angular 应用一般会同时使用 NgModule和 JavaScript 模块。JavaScript 将每个文件看作一个模块,文件中定义的所有对象都隶属于这个模块。模块对外提供的对象,需要使用export关键字进行标记导出。其它的 JavaScript 文件则使用import语句导入别的模块导出的对象。

现在再看前面的AppModule的代码。最初的几行import语句,从其它文件导入内容,而最后一行export语句,则是将AppModule导出,以便其它模块可以通过import导入AppModule模块。回顾一下 main.ts 中使用AppModule的情景。

现在我们介绍了 main.ts 以及@NgModule修饰器,知道了模块在 Angular 应用中的重要性。下一章我们将介绍 Angular 中另外一个重要的概念:组件。

Leave a Reply