Angular-CLI 与其整体架构

Angular-CLI 与其整体架构

因为年后公司项目转向 Angular 架构了,所以只有暂时性的放下 VueReact 相关内容,转向 Angular 方向了,俗话说得好,技多不压身,就当学习一门新的框架了,那么废话不多说,让我们从头开始,慢慢来啃 Angular 这块硬骨头吧

Angular2.x 之后的版本中相较与 1.x 的版本变化很多,说其为两个不同的框架也不为过,并且在新的版本当中,提供了一个 Angular-CLI 的脚手架,用于实现自动化开发工作流程,它可以创建一个新的 Angular 应用程序,并附带以下相关工具

  • 运行带有 LiveReload 支持的开发服务器,以便在开发过程中预览应用程序
  • 添加功能到现有的 Angular 应用程序(提供了一系列 ng xxx 相关命令)
  • 运行应用程序的单元测试
  • 运行应用程序的端到端(E2E)测试
  • 构建应用程序

那么就先从最基本的 Angular-CLI 生成的目录结构以及相关初始化入口文件开始

Angular-CLI 目录结构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
├── e2e                             // ==> 端到端
│ ├── app.e2e-spec.ts // ==> 端到端测试文件
│ ├── app.po.ts // ==> 端到端测试入口文件
│ └── tsconfig.e2e.json // ==> 用于端到端测试的 typescript 编译器的配置文件
├── node_modules // ==> 第三方依赖包
├── src // ==> 项目主文件所在目录
│ ├── app // ==> 组件所在文件夹
│ │ ├── app.component.css // ==> 组件的样式文件
│ │ ├── app.component.html // ==> 组件的 HTML 模板文件
│ │ ├── app.component.spec.ts // ==> 组件的单元测试文件
│ │ ├── app.component.ts // ==> 组件定义文件
│ │ └── app.module.ts // ==> 模块定义配置文件
│ ├── assets // ==> 静态资源
│ │ └── .gitkeep // ==> assets 目录用于存放图片等静态资源文件,构建时会拷贝到发布包里,新创建时一般为空
│ │ // ==> 但是由于 git 会忽略空文件夹,放置 .gitkeep 这个空文件以保证目录得到管理
│ ├── environments // ==> 环境
│ │ ├── environment.prod.ts // ==> 生产环境配置文件,在 .angular-cli.json 中被 mapping,mapping 值为 prod
│ │ └── environment.ts // ==> 开发环境配置,在 .angular-cli.json 中被 mapping,mapping 值为 dev
│ ├── favicon.ico // ==> 网页左上角显示的图标
│ ├── index.html // ==> 项目主页
│ ├── main.ts // ==> Angular 程序的入口
│ ├── polyfills.ts // ==> 不同浏览器,比如一些老旧的浏览器及版本的支持
│ ├── styles.css // ==> 全局的样式
│ ├── test.ts // ==> 单元测试入口
│ ├── tsconfig.app.json // ==> Angular 应用的 typescript 编译器的配置文件
│ ├── tsconfig.spec.json // ==> 单元测试的 typescirpt 编译器的配置文件
│ ├── tsconfig.app.json // ==> Angular 应用的 typescript 编译器的配置文件
│ └── typings.d.ts // ==> 项目中使用的 typescript 类型的引用文件
├── .angular-cli.json // ==> CLI 的配置文件,可以设定项目的基础信息,比如构建后的目标目录名称等
├── .editorconfig // ==> 编辑器的配置文件
├── .gitignore // ==> 为了保证自动生成的文件不被提交的 git 配置文件
├── karma.conf.js // ==> karma 单元测试的配置文件
├── package.json // ==> npm 的配置文件以及第三方依赖包
├── protractor.conf.js // ==> protractor 的端到端测试的配置文件
├── README.md // ==> 项目的基本信息,主要包含使用 cli 命令如何对项目进行 构建/测试/运行 等
├── tsconfig.json // ==> typescirpt 编译器的配置文件
└── tslint.json // ==> 提供给 TSLint 和 Codelyzer 的配置信息

以上就是使用 Angular-CLI 默认生成的文件结构,下面我们来梳理一下一个 Angular 应用的整体架构

整体架构

整体架构可以如下图所示

Angular 使用扩展语法编写 HTML 模版,使用组件对其进行管理,通过服务来添加应用逻辑,最后使用模块来对组件进行打包,通过引导根模块来启动应用,Angular 在浏览器中接管、展现应用的内容,根据操作指令响应用户的交互,Angular 的架构主要分为四大块

  • 组件,Angular 应用的基本构件块,可以简单的理解为一个组件就是一段带有业务逻辑和数据的 HTML
  • 指令,允许向 HTML 元素添加自定义行为
  • 模块,模块用来将应用中不同的部分组织成一个 Angular 框架可以理解的单元(组件)
  • 服务,用来封装可从用的业务逻辑

而整个启动过程是通过引导模块来进行的,每个 Angular 应用至少应该有一个模块,而此模块被称为根模块(App Module

根模块 @NgModule 装饰器

所谓的根模块,也就是我们的 app.module.ts 文件,如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { AppComponent } from './app.component'

// @NgModule 装饰器用来为模块定义元数据
@NgModule({
// declarations 列出了应用中的顶层组件,包括引导性组件 AppComponent 和我们自己创建的组件
// 在 module 里面声明的组件在 module 范围内都可以直接使用
// 也就是说在同一 module 里面的任何 Component 都可以在其模板文件中直接使用声明的组件
declarations: [
AppComponent,
...
],
// 引入相关依赖
// BrowserModule 提供了运行在浏览器中的应用所需要的关键服务(Service)和指令(Directive)
// 这个模块所有需要在浏览器中跑的应用都必须引用
imports: [
BrowserModule
],
// providers 列出会在此模块中 "注入" 的服务(Service)
providers: [],
// bootstrap 指明哪个组件为引导性组件(默认的是 AppComponent)
// 当 Angular 引导应用时,它会在 DOM 中渲染这个引导性组件
// 并把结果放进 index.html 的该组件的元素标签中(默认为 app-root)
bootstrap: [AppComponent]
})

export class AppModule { }

而根模块在 Angular 程序的入口 main.ts 中被使用,也就是所谓的引导过程,Angular 通过在 main.ts 中引导 AppModule 来启动应用,但是针对不同的平台 Angular 提供了很多引导选项,默认的采用是即时(JIT)编译器动态引导,一般多用在进行开发调试的时候

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// main.ts
// 连同 Angular 编译器一起发布到浏览器
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()
}

// 对 AppModule 进行引导
// Angular 编译器在浏览器中编译并引导该应用
platformBrowserDynamic().bootstrapModule(AppModule)
.catch(err => console.log(err))

另一种方式是使用预编译器(AoT - Ahead-Of-Time)进行静态引导,静态方案可以生成更小、启动更快的应用,建议优先使用它,特别是在移动设备或高延迟网络下,使用 static 选项,Angular 编译器作为构建流程的一部分提前运行,生成一组类工厂,它们的核心就是 AppModuleNgFactory,引导预编译的 AppModuleNgFactory 的语法和动态引导 AppModule 类的方式很相似

1
2
3
4
5
6
7
8
// 不把编译器发布到浏览器
import { platformBrowser } from '@angular/platform-browser'

// 静态编译器会生成一个 AppModule 的工厂 AppModuleNgFactory
import { AppModuleNgFactory } from './app.module.ngfactory'

// 引导 AppModuleNgFactory
platformBrowser().bootstrapModuleFactory(AppModuleNgFactory)

模块化

Anagulr 应用是模块化的,被称为 NgModule@NgModule 是一个装饰器,装饰器其实是函数,是用来装饰函数,它可以把元数据附加到类上,NgModule 装饰器用来描述模块属性,常见的模块属性如下所示

属性 说明
declarations 声明本模块中拥有的视图类,Angular 有三种视图类,即组件,指令和管道
exports declarations 的子集,可用于其他模块的组件模版
imports 本模块声明的组件模板需要的类所在的其他模块
providers 服务的创建者,并加入到全局服务列表中,可用于应用任何部分
bootstrap 指定应用的主视图(根组件),它是所有其他视图的宿主

这里有两个地方需要注意

  • exports 属性并不是必须的,因为其他组件无需导入根模块,所以根模块也不需要导出
  • 只有根模块才能设置 bootstrap 属性

组件

@NgModule 类似,@ComponentAngular 的组件装饰器,主要属性如下

属性 说明
selector CSS 选择器,它告诉 Angular 在父级 HTML 中查找 selector 中定义的标签,创建并插入该组件
template/templateUrl 组件或者组件 HTML 模块的相对地址
providers 组件所需服务的依赖注入提供商数组,这是在告诉 Angular 该组件的构造函数可能需要一个服务,这样组件就可以从服务中获得数据

在根模块的 bootstrap 属性中设定了 AppComponent 组件,说明根模块引导的为 AppComponent 组件

1
2
3
4
5
6
7
8
9
10
11
import { Component } from '@angular/core'

@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})

export class AppComponent {
title = 'Angular Examples'
}
  • 装饰器 @Component 将三个东西结合在了一起,selectorHTML 模板以及 CSS 样式
  • 通过插值的方式保证数据进行交互和传递
  • 通过修改填充的内容则可以直接影响输出
  • 通过 CSS 样式直接调整显示,做到数据和显示的分离

这也就是整体 Angular 程序的启动过程,不过特别需要注意的是

当组件编写完成后还需要进行组件声明后才能使用,每个组件都必须在一个 Angular 模块而且只能在一个 Angular 模块中进行声明

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×