目录
编者注:本篇博客重要的是第一章基本原理。
app目录 包含应用的组件和模块,我们要写的代码都在这个目录
index.html 整个应用的根html,程序启动就是访问这个页面
main.ts 整个项目的入口点,Angular通过这个文件来启动项目
1. 基本原理(重要)
1.1 搭建本地开发环境和工作空间
首先确保开发环境有node.js和npm,然后就可以使用 Angular CLI 来创建项目、生成应用和库代码,以及执行各种持续开发任务,比如测试、打包和部署。Angular CLI 中包含一个服务器,方便你在本地构建和提供应用。
控制台输入npm install -g @angular/cli 来安装angular CLI,ng new my-app新建工作空间,cd my-app进去工作空间,然后ng serve --open就可以启动开发服务器。
有了angular CLI就不用webpack了。
1.2 angular架构概览
Angular 是一个用 HTML 和 TypeScript 构建客户端应用的平台与框架。 Angular 本身就是用 TypeScript 写成的。它将核心功能和可选功能作为一组 TypeScript 库进行实现,你可以把它们导入你的应用中。
Angular 的基本构造块是 NgModule模块,它为component组件提供了编译的上下文环境。 组件定义html视图,组件使用service服务。
组件和服务都是简单的类,这些类使用装饰器来标出它们的类型,并提供元数据以告知 Angular 该如何使用它们。
- 组件类的元数据将组件类和一个用来定义视图的模板关联起来。
- 服务类的元数据提供了一些信息,Angular 要用这些信息来让组件可以通过依赖注入(DI)使用该服务。
应用的组件通常会定义很多视图,并进行分级组织。 Angular通过 Router模块提供的
服务来帮助你定义视图之间的导航路径。 路由器提供了先进的浏览器内导航功能。
1.3 补充
装饰器是一些用于修饰 JavaScript 类的函数,在angular里表示这个类要接受一个元数据对象,该对象的属性用来描述这个类。
- 对于模块:
@NgModule()
装饰器的类。模块可以将其组件和一组相关代码(如服务)关联起来,形成功能单元。 - 对于组件:
@Component()
装饰器表明紧随它的那个类是一个组件,并提供模板和该组件专属的元数据。 - 对于服务:@Injectable() 装饰器表明紧随它的那个类是一个服务类。该装饰器提供的元数据可以让你的服务作为依赖被注入到客户组件中。因此,组件可以通过服务来:从服务器获取数据、验证用户输入或直接把日志写到控制台等。
每个 Angular 应用都有一个根模块,通常命名为 AppModule
。根模块提供了用来启动应用的引导机制。 一个应用通常会包含很多功能模块。它会把组件树和页面中的 DOM 连接起来。
总结一下:通过以上就要知道模块、组件、服务、路由在angular框架中是怎么作用的。
2. 具体细节
2.1 模块和组件
app.component.ts:这个文件表示组件,组件是Angular应用的基本构建模块,可以理解为一段带有业务逻辑和数据的Html,例子如下:
/*这里是从Angular核心模块里面引入了component装饰器*/
import {Component} from '@angular/core';
/*用装饰器定义了一个组件以及组件的元数据 所有的组件都必须使用这个装饰器来注解*/
@Component({
/*组件元数据 Angular会通过这里面的属性来渲染组件并执行逻辑
* selector就是css选择器,表示这个组件可以通过app-root来调用,index.html中有个<app-root>Loading...</app-root>标签,这个标签用来展示该组件的内容
*templateUrl 组件的模板,定义了组件的布局和内容
*styleUrls 该模板引用那个css样式
* */
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
/*AppComponent本来就是一个普通的typescript类,但是上面的组件元数据装饰器告诉Angular,AppComponent是一个组件,需要把一些元数据附加到这个类上,Angular就会把AppComponent当组件来处理*/
export class AppComponent {
/*这个类实际上就是该组件的控制器,我们的业务逻辑就是在这个类中编写*/
title = '学习Angular';
}
app.module.ts:这个文件表示模块,与AppComponent类似,模块也需要装饰器来装饰。
@NgModule()
装饰器是一个函数,它接受一个元数据对象,该对象的属性用来描述这个模块。其中最重要的属性如下:
declaration、exports、imports、bootstrap、providers(这些服务能被本应用中的任何部分使用。)
把 app-product-alerts
组件(就是它显示的“nnn”按钮)的 notify
事件绑定到商品列表组件的 onNotify()
方法。
父组件:商品列表组件;子组件:新商品提醒组件
@Component配置:selector、templateUrl、providers
2.2 路由
用法提示:[routerLink]="['/products', productId]"
import { ActivatedRoute } from '@angular/router';
使用 RouterLink
指令定义一个链接。routerLink
定义了如何在组件模板中声明式的导航到指定路由(或 URL)。
import ActivatedRoute
:用于由 Angular 路由器加载的每个路由组件。它包含关于该路由,路由参数以及与该路由关联的其它数据的信息。
<router-outlet></router-outlet>:页面的占位符,动态加载,会被替换掉的。
RouterModule.forRoot:forRoot是用在根模块加载路由配置,而forChild是用在子模块加载路由配置。
2.3 服务与依赖注入
对于与特定视图无关并希望跨组件共享的数据或逻辑,可以创建服务类。 服务类的定义通常紧跟在 “@Injectable()” 装饰器之后。该装饰器提供的元数据可以让你的服务作为依赖被注入到客户组件中。狭义的服务是一个明确定义了用途的类。
在 Angular 中,要把一个类定义为服务,就要用 @Injectable()
装饰器来提供元数据,以便让 Angular 可以把它作为依赖注入到组件中。 同样,也要使用 @Injectable()
装饰器来表明一个组件或其它类(比如另一个服务、管道或 NgModule)拥有一个依赖。也就是说,你可以把一个服务注入到组件中,让组件类得以访问该服务类。
2. 4 父子组件传值
传值都是子组件import Input、Output。
父传子:子组件通过@Input() 接收。使用@Input装饰变量input(要与父组件中[]中的变量一致),即可接收父组件中传来的值。即通过“[输入属性]=输入值”的方式传值,给属性打上中括号代表输入。
子传父:子组件需要实例化EventEmitter类来订阅和触发自定义事件。调用emit()方法触发当前实例上的事件。要依赖如click这样的事件来触发。父组件接收时是通过捕获发射事件得到值。
2.5 其它
开发中我们经常在ngOnInit
做一些初始化的工作,而这些工作尽量要避免在constructor
中进行,constructor
中应该只进行依赖注入、变量初始化,而不是进行真正的业务操作。
服务可用于跨组件共享数据。方法:在组件的ts先导入该服务,再在constructor中注入该服务。
在项目开发中我们要尽量保持构造函数简单明了,让它只执行简单的数据初始化操作,因此我们会把其他的初始化操作放在 ngOnInit 钩子中去执行。如在组件获取输入属性之后,需执行组件初始化操作等。
为应用启用HttpClient。
在购物车里的product-list.component.ts的
export class ProductListComponent {
products = products;}
这块相当于把 等号左边products这个products.ts赋值给了products。有点像:
constructor(
private route: ActivatedRoute,
private cartService1: CartService,
) { }
但是constructor里面的CartService是更高级的东西,它有逻辑、数据、方法等。
1. product-details.component.ts 里为啥不用products = products?
而product-list.component.ts 里有products = products。
2. 利用 async 管道修改配送组件的模板,以显示配送类型和价格:src/app/shipping/shipping.component.html
3.使用 formGroup
属性绑定把 checkoutForm
绑定到模板中的 form
标签上。src/app/cart/cart.component.html
2.6 表单
FormControl
实例用于追踪单个表单控件的值和验证状态。
FormGroup
用于追踪一个表单控件组的值和状态。
FormArray
用于追踪表单控件数组的值和状态。
FormBuilder 服务有三个方法:control()、group() 和 array()。这些方法都是工厂方法,用于在组件类中分别生成FormControl、FormGroup 和 FormArray。你可以使用 group() 方法,用和前面一样的名字来定义这些属性。
FormBuilder
服务是由 ReactiveFormsModule
提供的,它已经在之前修改过的 AppModule
定义过。在 app.module.ts:
import { ReactiveFormsModule } from '@angular/forms'; 。只要把它添加到组件的构造函数中就可以注入这个依赖。
快速起步:注册ReactiveFormsModule ==》 生成并导入表单控件 ==》 在模板中注册该控件
修改模板,为表单控件添加 formControl
绑定,formControl
是由 ReactiveFormsModule
的 FormControlDirective
提供的。
export class NameEditorComponent {
name = new FormControl('');
<label>
Name:
<input type="text" [formControl]="name">
</label>
使用这种模板绑定语法,把该表单控件注册给了模板中名为 name
的输入元素。这样,表单控件和 DOM 元素就可以互相通讯了。
比较一下表单构造器和手动创建实例这两种方式:
<form [formGroup]="profileForm" (ngSubmit)="onSubmit()">
profileForm 这个 FormGroup
也通过 FormGroup
指令绑定到了 form
元素,在该模型和表单中的输入框之间创建了一个通讯层。 由 FormControlName
指令提供的 formControlName
属性把每个输入框和 FormGroup
中定义的表单控件绑定起来。这些表单控件会和相应的元素通讯,它们还把更改传递给 FormGroup
,这个 FormGroup
是模型值的权威数据源。
form
标签上,使用 ngSubmit
事件绑定来监听表单提交,并使用 checkoutForm
值调用 onSubmit()
方法:
<form [formGroup]="checkoutForm" (ngSubmit)="onSubmit(checkoutForm.value)">
</form>
2.7 管道
管道 是格式化字符串、金额、日期和其它显示数据的好办法。 Angular 发布了一些内置管道,而且你还可以创建自己的管道。