angular5基础笔记
Posted 咖啡壶子
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了angular5基础笔记相关的知识,希望对你有一定的参考价值。
这里写目录标题
- 第 1 章 Angular 初识
- 第 2 章 架构概览
- 第 3 章 内置指令
- 第 4 章 数据绑定
- 第 5 章 TypeScript
- 第 6 章 表单
- 第 7 章 组件
- 第8章 管道
- 第 9 章 依赖注入
- 第 10 章 HttpClient 库
- 第 11 章 路由和导航
第 1 章 Angular 初识
1.1 Angular 简介
Angular 是一个开发平台。它能帮你更轻松的构建 Web 应用。Angular 集声明式模板、依赖注入、端到端工具和一些最佳实践于一身,为你解决开发方面的各种挑战。Angular 为开发者提升构建 Web、手机或桌面应用的能力。
1.1.1 AngularJS 和 Angular2.x、Angular4.x、Angular5.x的区别?
AngularJS 可以看成是 Angular1.x 版本,与 Angular2.x 以后的版本相比差别非常大,从 2.x 版本开始支TypeScript/javascript/Dart, 而不再是 JavaScript。 但是之后的版本都是向前兼容,差别不会太大。也就是说,理想情况下, 4 的程序是可以直接迁移到 5 的, 只是会收到一些API 废弃示, 到 6 中才会彻底移除。 同时, 官方会在文档中给出详细的升级指南, 帮助开发者升级。
1.1.2 为什么没有 Angular3.x?
简单点说就是因为路由模块比其他模块多发布过一次, 因此当你使用 core 模块的 2.0 时, 和它配套的 router 模块却是 3.0 的, 这容易让开发人员困惑,跳过 3, 可以让所有模块的编号重新对齐。 语义化命名版本规则(参考:http://semver.org/lang/zh-CN/)
1.2 环境搭建
1.2.1 Typescript 和 npm
Angular 本 身 就 是 Typescript 写 的 , 所 以 开 发 ng 项 目 一 般 都 采 用Typescript 语法编写,当然也可以使用 ES5 API,但是不建议。npm 是 NodeJS 自带的一个包管理工具,所以要提前安装好 NodeJS。
1.2.2 Angular CLI
好的工具能让开发更加简单快捷。Angular CLI 是一个命令行界面工具,它可以创建项目、添加文件以及执行一大堆开发任务,比如测试、打包和发布。
1.2.2.1 全局安装 CLI
npm install -g @angular/cli
1.2.2.2 创建新项目
ng new my-app
1.2.2.3 启动开发服务器
进入项目目录,安装依赖,并启动应用
cd my-app
npm install
ng serve --open
ng serve 命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建 此 应 用 。 使 用 --open ( 或 -o ) 参 数 可 以 自 动 打 开 浏 览 器 并 访 问http://localhost:4200/。
ng serve 命令会启动开发服务器,监听文件变化,并在修改这些文件时重新构建 此 应 用 。 使 用 --open ( 或 -o ) 参 数 可 以 自 动 打 开 浏 览 器 并 访 问http://localhost:4200/。
1.3 编辑第一个 Angular 组件
这个 CLI 为我们创建了第一个 Angular 组件。 它就是名叫 app-root 的根组件。 在./src/app/app.component.ts 目录下找到它。打开这个组件文件,并且把 title 属性从 Welcome to app!! 改为 WelcometoMyFirstAngularApp!!
export class AppComponent
title = 'Welcome to My First Angular App!! ';
浏览器会自动刷新,而我们会看到修改之后的标题。不错,不过它还可以更好看一点。打开src/app/app.component.css 并给这个组件设置一些样式:
h1
color: #369;
font-family: Arial, Helvetica, sans-serif;
font-size: 250%;
1.4 项目结构
src 文件夹
- app 目录存放组件以及后续新增组件,
- app/app.module.ts 定义 AppModule,这个根模块会告诉 Angular 如何组装该应用。
- assets 目录存放静态资源文件,比如图片
- index.html 网站主页面
- main.ts 应用主入口
第 2 章 架构概览
Angular 是 一 个 用 HTML 和 JavaScript 或 者 一 个 可 以 编 译 成JavaScript 的语言(例如 Dart 或者 TypeScript ),来构建客户端应用的框架。该框架包括一系列库,有些是核心库,有些是可选库。
我们是这样写 Angular 应用的:
- 用 Angular 扩展语法编写 HTML 模板,
- 用组件类管理这些模板,
- 用服务添加应用逻辑, 用模块打包发布组件与服务。
- 然后,我们通过引导根模块来启动该应用。
- Angular 在浏览器中接管、展现应用的内容,并根据我们提供的操作指令响应用户的交互。
- Angular 架构中核心概念有:模块、组件、模板、元数据、数据绑定、指令、服务、依赖注入。
2.1 模块
Angular 应用是模块化的,并且 Angular 有自己的模块系统,它被称为 Angular 模块或 NgModules,Angular 模块很重要。
每个 Angular 应用至少有一个模块(根模块),习惯上命名为 AppModule。
Angular 模块(无论是根模块还是特性模块)都是一个带有@NgModule 装饰器的类。
装饰器是用来修饰 JavaScript 类的函数。 Angular 有很多装饰器,它们负责把元数据附加到类上,以了解那些类的设计意图以及它们应如何工作。
下面查看一下项目的根模块:app.module.ts
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
NgModule 是一个装饰器函数,它接收一个用来描述模块属性的元数据对象。其
中最重要的属性是:
- declarations - 声明本模块中拥有的视图类。Angular 有三种视图类:
组件、指令和管道。 - exports - declarations 的子集,可用于其它模块的组件模板。
- imports - 本模块声明的组件模板需要的类所在的其它模块。
- providers - 服务的创建者,并加入到全局服务列表中,可用于应用任何部分。
- bootstrap - 指定应用的主视图(称为根组件),它是所有其它视图的宿主。只有根模块才能设置 bootstrap 属性。
2.2 组件
组件负责控制屏幕上的一小块区域,我们称之为视图。我们在类中定义组件的应用逻辑,为视图提供支持。
查看一个最简单的组件:app.component.ts
import Component from '@angular/core';
@Component(
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
)
export class AppComponent
title = 'Welcome to My First Angular App!! ';
Component 组件中的@Component 装饰器有很多属性,这是一部分:
- selector - 组件名称,在使用是通过引用组件。
- templateUrl - 模板 HTML,引入外部 html 作为模板。也可以直接使用template 属性定义模板字符串。
- styleUrls - 模板样式,引入外部 css 文件。也可以使用 style 属性来定义样式字符串
2.3 模板
通过组件的自带的模板来定义组件视图。模板以 HTML 形式存在,告诉Angular 如何渲染组件。
模板文件:app.component.html
<div style="text-align:center">
<h1>
Welcome to title!
</h1>
</div>
通过 templateUrl: './app.component.html'
引用,或者直接使用:
template:`
<div style="text-align:center">
<h1>
Welcome to title!
</h1>
</div>
`
2.4 元数据
metadata 元 数 据 告 诉 Angular 如 何 处 理 一 个 类 , 用 装 饰 器(decorator) 来附加元数据给一个类 class, Angular 就会把它作为一个组件。
@Component(
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
)
export class AppComponent
//组件
这里看到@Component 装饰器,它把紧随其后的类标记成了组件类。
2.5 数据绑定
Angular 支持数据绑定,一种让模板的各部分与组件的各部分相互合作的机制。 我们往模板 HTML 中添加绑定标记,来告诉 Angular 如何把二者联系起来。
数据绑定的语法有四种形式。每种形式都有一个方向 —— 绑定到DOM 、绑定自 DOM 以及双向绑定。简单理解就是:取值、单向绑定、事件绑定、双向绑定。
2.6 指令
Angular模板是动态的。当 Angular渲染它们时,它会根据指令(directive)提供的操作对 DOM 进行转换。
组件是一个带模板的指令,还有两种其它类型的指令:结构型指令和属性(attribute) 型指令。
它们往往像属性 (attribute) 一样出现在元素标签中,偶尔会以名字的形式出现,但多数时候还是作为赋值目标或绑定目标出现。
2.6.1 结构型指令
结构型指令通过在 DOM 中添加、移除和替换元素来修改布局。
<li *ngFor="let hero of heroes"></li>
<app-hero-detail *ngIf="selectedHero"></app-hero-detail>
2.6.2 属性型指令
属性型指令修改一个现有元素的外观或行为。 在模板中,它们看起来就像是标准的 HTML 属性,故名。
<input [(ngModel)]="hero.name">
Angular 还有少量指令,它们或者修改结构布局(例如 ngSwitch), 或者修改 DOM 元素和组件的各个方面(例如 ngStyle 和 ngClass)。当然,我们也能编写自己的指令。
2.7 服务
服务是一个广义范畴,包括:值、函数,或应用所需的特性。
几乎任何东西都可以是一个服务。 典型的服务是一个类,具有专注的、明确的用途。它应该做一件特定的事情,并把它做好。
例如:
- 日志服务
- 数据服务
- 消息总线
- 税款计算器
- 应用程序配置
服务无处不在,组件类应保持精简。
组件本身不从服务器获得数据、不进行验证输入,也不直接往控制台写日志。 它们把这些任务委托给服务。
组件的任务就是提供用户体验,仅此而已。它介于视图(由模板渲染)和应用逻辑(通常包括模型的某些概念)之间。 设计良好的组件为数据绑定提供属性和方法,把其它琐事都委托给服务。
2.8 依赖注入
“依赖注入”Dependency injection 是提供类的新实例的一种方式,还负责处理好类所需的全部依赖。大多数依赖都是服务。 Angular 使用依赖注入来提供新组件以及组件所需的服务。
constructor(private service: HeroService)
当 Angular 创建组件时,会首先为组件所需的服务请求一个注入器(injector)。
注入器维护了一个服务实例的容器,存放着以前创建的实例。
如果所请求的服务实例不在容器中,注入器就会创建一个服务实例,并且添加到容器中,然后把这个服务返回给 Angular。
当所有请求的服务都被解析完并返回时,Angular 会以这些服务为参数去调用组件的构造函数。 这就是依赖注入 。
我们可以在模块中或组件中注册提供商。通常会把提供商添加到根模块上,以便在任何地方都使用服务的同一个实例。
@NgModule(
providers: [HeroService]
)
或者,也可以在@Component 元数据中的 providers 属性中把它注册在组件层:
@Component(
selector: 'app-root',
providers: [ HeroService ]
)
把它注册在组件级表示该组件的每一个新实例都会有一个服务的新实例。
需要记住的关于依赖注入的要点是:
- 依赖注入渗透在整个 Angular 框架中,被到处使用。
- 注入器 (injector) 是本机制的核心。
- 注入器负责维护一个容器,用于存放它创建过的服务实例。
- 注入器能使用提供商创建一个新的服务实例。
- 提供商是一个用于创建服务的配方。
- 把提供商注册到注入器。
第 3 章 内置指令
3.1 创建第一个自己的组件
3.1.1 定义组件
新建 hello-world.component.ts 模块文件,模块命名一般要 component来表示是一个模块。
import Component from '@angular/core';
@Component(
selector: 'app-hello-world',
template: `
<h3>greetText</h3>
`
)
export class HelloWorldComponent
greetText = 'hello world!!';
通过@Component 装饰器定义组件,selector 定义组件的引用名称为app-hello-world,template 定义模板的 html 片段,注意使用的是 ES6的模板字符串``,当然也可以使用普通字符串,但是不建议。双花括号进行取值,class 来声明一个组件类,greetText 是定一个的组件变量。
3.1.2 声明组件
要在 Angular 模块中使用新定义的组件,需要先声明组件。把定义好的组件import 到 app.mudule.ts 根模块中,并在@NgModule 中的 declarations中声明才能使用。
import HelloWorldComponent from './hello-world.component'
@NgModule(
declarations: [
AppComponent,
HelloWorldComponent
],
...
)
3.1.3 使用组件
在 app.component.html 文件中引用组件
<app-hello-world></app-hello-world>
页面中就会看到:hello world!! 现在我们已经定义好了一个属于自己的组
件了。
3.1.4 使用 CLI 创建组件
手动创建组件时,每次都需要自己添加新的组件到根模块中,比较繁琐。我们可以通过CLI命令来创建我们的Angular组件,他会自动帮我们添加到根模块中,创建一个新的 hello-everyone 模块:
ng generate component hello-everyone
同时 app.module.ts 根模块也同步更新。
3.2 ngIf
它接受一个布尔值,并据此让一整块 DOM 树出现或消失。
<p *ngIf="true">
你能看到我!- true
</p>
<p *ngIf="false">
你能看不到我!- false
</p>
ngIf 指令并不是使用 CSS 来隐藏元素的。它会把这些元素从 DOM 中物理删除。
3.3 ngFor
循环遍历一个数组或者对象。
citys = ['shanghai', 'beijing', 'hangzhnou'];//在组件中定义
<ul>
<li *ngFor="let city of citys">
city
</li>
</ul>
NgFor 的全特性应用:
//数据
fruits = [
id:1, name:'apple',
id:2, name:'bananer',
id:3, name:'orange'
];
<ul>
<li *ngFor="let fruit of fruits; let i=index; let odd=odd;
trackBy: trackById">
名称:fruit.name - 索引:i - 偶数行:odd
</li>
</ul>
3.4 NgSwitch
NgSwitch 指令由:NgSwitch、NgSwitchCase 和 NgSwitchDefault 组
成。
<div [ngSwitch]="myChar">
<p *ngSwitchCase="'A'">
myChar is A
</p>
<p *ngSwitchCase="'B'">
myChar is B
</p>
<p *ngSwitchDefault>
myChar is not A and B
</p>
</div>
3.5 NgStyle
样式绑定,可以设置内联样式。
方括号中的部分不是元素的属性名,而由 style 前缀,一个点 (.)和 CSS 样式的属性名组成。 形如:[style.style-property]。
3.5.1 [style.style-property]
<button [style.color]="'red'">Red</button>
<button [style.color]="false ? 'red' : 'blue'">Blue</button>
3.5.2 带单位
有些样式绑定中的样式带有单位。在这里,以根据条件用“px”、 “em” 和 “%”来设置字体大小的单位。
<button [style.font-size.px]="20">Red</button>
<button [style.font-size.em]="2">Red</button>
<button [style.font-size.%]="100">Red</button>
3.5.3 ngStyle
同时操作多个属性,可以传入一个对象
<button [ngStyle]="'font-size':'20px'">Red</button>
3.6 NgClass
借助 CSS 类绑定,可以从元素的 class attribute 上添加和移除 CSS 类名。
方括号中的部分不是元素的属性名,而是由 class 前缀,一个点 (.)和 CSS 类的名字组成, 其中后两部分是可选的。形如:[class.class-name]。
3.6.1 class 属性绑定
<div [class]="'container'">hello</div>
3.6.2 class 和[class]
class 和[class]共存时,如果[class]有值会完全覆盖 class。
<div class="box" [class]="'container'">hello</div>
3.6.3 [class.class-name]
最后,可以绑定到特定的类名。 当模板表达式的求值结果是真值时,Angular会添加这个类,反之则移除它
<div class="box" [class.container]="true">hello</div>
<div class="box" [class.container]="fasle">hello</div>
3.6.4 ngClass
同时操作多个 class 类,可以传入一个对象
<div [ngClass]="box:true, container:false">hello</div>
3.7 ngNonBindable
当我们想告诉 Angular 不要编译或者绑定页面中的某个特殊部分时, 要使用 ngNodBindable 指令。
<div ngNonBindable>
使用 content 获取值
</div>
3.8 自定义指令
属性型指令至少需要一个带有@Directive 装饰器的控制器类。该装饰器指定了一个用于标识属性的选择器。 控制器类实现了指令需要的指令行为。
创建一个简单的属性型指令 myHighlight ,当用户把鼠标悬停在一个元素上时,改变它的背景色。你可以这样用它:
<p appHighlight>heightLight</p>
3.8.1 编写指令代码
import Directive, ElementRef from '@angular/core';
@Directive(
selector: '[appHighlight]',
)
export class HightlightDirective
constructor(el: ElementRef)
el.nativeElement.style.backgroundColor = 'yellow';
ElementRef 对象可以获取指定绑定的 DOM 元素,通过 nativeElement 来操作 DOM。
3.8.2 添加到根模块
import HightlightDirective from
'./directive/highlight.directive'
@NgModule(
declarations: [
AppComponent,
HightlightDirective
],
3.8.3 通过事件触发
当前,appHighlight 只是简单的设置元素的颜色。 这个指令应该在用户鼠标悬浮一个元素时,设置它的颜色。先把 HostListener 加进导入列表中,同时再添加 Input 装饰器。
import Directive, ElementRef, HostListener from
'@angular/core';
@Directive(
selector: '[appHighlight]',
)
export class HightlightDirective
constructor(private el: ElementRef)
private highlight(color: string)
this.el.nativeElement.style.backgroundColor = color;
@HostListener('mouseenter') onmouseenter()
this.highlight('yellow');
@HostListener('mouseleave') onmouseleave()
this.highlight(null);
3.8.4 自定义颜色
现在的高亮颜色是硬编码在指令中的,这不够灵活。 我们应该让指令的使用者可以在模板中通过绑定来设置颜色。
import Directive, ElementRef, HostListener, Input from
'@angular/core';
@Directive(
selector: '[appHighlight]',
)
export class HightlightDirective
@Input() appHighlight;
constructor(private el: ElementRef)
private highlight(color: string)
this.el.nativeElement.style.backgroundColor = color;
@HostListener('mouseenter') onmouseenter()
this.highlight(this.appHighlight || 'yellow');
@HostListener('mouseleave') onmouseleave()
this.highlight(null);
使用:
<p [appHighlight]="'green'">heightLight-green</p>
第 4 章 数据绑定
4.1 属性绑定
当要把视图元素的属性 (property) 设置为模板表达式时,就要写模板的属性(property) 绑定。数据流动方向是从等号右边流入左边。
最常用的属性绑定是把元素属性设置为组件属性的值。下面这个例子中,image元素的 src 属性会被绑定到组件的 imageUrl 属性上:
<img [src]="imageUrl">
另一个例子是当组件说它 isUnchanged(未改变)时禁用按钮:
<button [disabled]="isUnchanged">Cancel is disabled</button>
4.2 事件绑定
常常需要监听某些事件,如按键、鼠标移动、点击和触摸屏幕。事件绑定语法由等号左侧带圆括号的目标事件和右侧引号中的模板语句组成。 数据流动方向从等号左边到右边。下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 onSave()方法。
onSave()
console.log('save...');
<button (click)="onSave()">Save</button>
4.2.1 $event
当事件发生时,这个处理器会执行模板语句。 典型的模板语句通常涉及到响应事件执行动作的接收器,例如从 HTML 控件中取得值,并存入模型。
事件对象的形态取决于目标事件。如果目标事件是原生 DOM 元素事件, $event 就是 DOM 事件对象,它有像 target 和 target.value 这样的属性。
show(event)
console.log(event, event.target, event.target.value);
<input (input)="show($event)" >
4.2.2 自定义事件
通常,指令使用 Angular EventEmitter 来触发自定义事件。 指令创建一个 EventEmitter 实 例 , 并 且 把 它 作 为 属 性 暴 露 出 来 。 指 令 调 用EventEmitter.emit(payload)来触发事件,可以传入任何东西作为消息载荷。 父指令通过绑定到这个属性来监听事件,并通过$event 对象来访问载荷。
4.2.2.1 创建新组件
import Component, EventEmitter, Output from '@angular/core';
@Component(
selector: 'app-self-event',
template: `
<button (click)="save()">self-event</button>
`
)
export class SelfEventComponent
@Output() myClick = new EventEmitter();
save()
this.myClick.emit('self-event');
首先引入 EventEmitter 和 Output 组件,@Output 装饰器定义这是一个输出变量,在这里就是从子组件输出到父组件。
4.2.2.2 父组件引用子组件
在 html 中引用组件
<app-self-event (myClick)="onMyClick($event)"></app-self-event>
在父组件中定义事件处理
onMyClick(event)
console.log(event);
4.2.2.3 子组件添加到根模块
别忘了把新定义的组件添加到根模块中,否则会报错。
import SelfEventComponent from
'./directive/self-event.componet'
@NgModule(
declarations: [
AppComponent,
DirectiveComponent,
SelfEventComponent
],
imports: [
BrowserModule
],
providers: [],
bootstrap: [AppComponent]
)
现在点击页面的按钮即可触发自定义事件 myClick 的执行。
4.3 双向绑定
我们经常需要显示数据属性,并在用户作出更改时更新该属性。在元素层面上,既要设置元素属性,又要监听元素事件变化。Angular 为此提供一种特殊的双向数据绑定语法:[(x)]。
结合了属性绑定的方括号[x]和事件绑定的圆括号(x)。
当一个元素拥有可以设置的属性 x 和对应的事件 xChange 时,解释[(x)]语法就容易多了。
4.3.1 [(x)] 语法
下面的 Component 符合这个模式。它有 size 属性和伴随的 sizeChange 事件:
import Component, Input, Output, EventEmitter from
'@angular/core';
@Component(
selector: 'app-two-way',
template: `
<div>
<button (click)="dec()" title="smaller">-</button>
<button (click)="inc()" title="bigger">+</button>
<label [style.font-size.px]="size">FontSize: sizepx</label>
</div>`
)
export class TwoWayComponent
@Input() size: number;
@Output() sizeChange = new EventEmitter();
dec()
this.sizeChange.emit(this.size--);
inc()
this.sizeChange.emit(this.size++);
父组件引用,记得在在父组件中记得定义 fontSize 属性。
<app-two-way [(size)]="fontSizePx"></app-two-way>
<div [style.font-size.px]="fontSizePx">双向绑定</div>
这里的 size 就是双向数据绑定,可以看成是 size 和 sizeChange 自定义事件的简写。其实,双向绑定语法实际上是属性绑定和事件绑定的语法糖。
Angular 将 Component 的绑定分解成这样:
<app-two-way [size]="fontSizePx"
(sizeChange)="fontSizePx=$event"></app-two-way>
e
v
e
n
t
变
量
包
含
了
S
i
z
e
r
C
o
m
p
o
n
e
n
t
.
s
i
z
e
C
h
a
n
g
e
事
件
的
荷
载
。
当
用
户
点
击
按
钮
时
,
A
n
g
u
l
a
r
将
event 变量包含了 SizerComponent.sizeChange 事件的荷载。 当用户点击按钮时,Angular 将
event变量包含了SizerComponent.sizeChange事件的荷载。当用户点击按钮时,Angular将event 赋值给 AppComponent.fontSizePx。
显然,比起单独绑定属性和事件,双向数据绑定语法显得非常方便。
4.3.2 NgModel
使用[(ngModel)]双向绑定到表单元素。当开发数据输入表单时,我们通常都要既显示数据属性又根据用户的更改去修改那个属性。
使用 NgModel 指令进行双向数据绑定可以简化这种工作。例子如下:
<div>
<input type="text" [(ngModel)]="fontSizePx">
</div>
但此时还不生效,需要在根模块引入 FormsModule,
import FormsModule from '@angular/forms';
@NgModule(
...
imports: [
BrowserModule,
FormsModule
],
providers: [],
bootstrap: [AppComponent]
)
export class AppModule
4.4 @Input 和@Output 别名
4.4.1 @Output
给输入/输出属性起别名,有时需要让输入/输出属性的公开名字不同于内部名字。比如自定义事件外部叫myClick,内部是使用 innerClick,
格式: ==@Output(外部公开名称) 内部使用名称 = ==
@Output('myClick') innerClick = new EventEmitter();
save()
this.innerClick.emit('self-event');
或者在@Component 中定义,使用
格式:outputs:[内部使用名称:外部公开名称]
@Component(
selector: 'app-self-event',
outputs:['innerClick: myClick'],
template: `
<button (click)="save()">self-event</button>
`
)
4.4.2 @Input
用法同@Output,假如外部传入 size 属性,内部使用 mySize 属性:
@Input('size') mySize: number;
或者在@Component 中定义:
inputs: ['mySize: size'],
4.5 模板引用变量 ( #var )
模板引用变量通常用来引用模板中的某个 DOM 元素,它还可以引用 Angular 组件或指令或 Web Component。使用井号 (#) 来声明引用变量。 #phone 的意思就是声明一个名叫 phone 的变量来引用元素。
<input #phone placeholder="phone number">
<button (click)="callPhone(phone.value)">Call</button>
不要在同一个模板中多次定义同一个变量名,否则它在运行期间的值是无法确定的。
我们也可以用 ref-前缀代替#。 下面的例子中就用把 phone 变量声明成了ref-phone 而不是#phone。
<input ref-phone placeholder="phone number">
<button (click)="callPhone(phone.value)">Phone</button>
4.6 安全导航符?.
Angular 的安全导航操作符 (?.) 是一种流畅而便利的方式,用来保护出现在属性路径中 null 和 undefined 值。 下例中,当 people 为空时,保护视图渲染器,让它免于失败。
<p> 你的名字:people?.name </p>
第 5 章 TypeScript
5.1 Angular 是用 TypeScript 构建的
Angular 是用 TypeScript 构建的,或许你会对用新语言来开发 Angular 心存疑虑, 但事实上, 在开发 Angular 应用时, 我们有充分的理由用TypeScript 代替普通的 JavaScript。
TypeScript 并不是一门全新的语言, 而是 ES6 的超集。 所有的 ES6 代码都是完全有效且可编译的 TypeScript 代码。 下图展示了它们之间的关系。
ES5 是 ECMAScript 5 的缩写, 也被称为“普通的 JavaScript”。 ES5 就是大家熟知的 JavaScript, 它能够运行在大部分浏览器上。 ES6 则是下一个版本的 JavaScript, 已经于 2015 年发布。
从 TypeScript 代码到 ES5 代码的唯一转换器是由 TypeScript 核心团队编写的。 然而, 将 ES6 代码(不是 TypeScript 代码) 转换到 ES5 代码则有两个主要的转换器: Google 开发的 Traceur 与 JavaScript 社区创建的 Babel 。 安装 TypeScript 环境:
npm install -g typescript
5.2 TypeScript 提供了哪些特性
TypeScript 相对于 ES5 有五大改善:
- 类型
- 类
- 注解
- 模块导入
- 语言工具包(比如, 解构)
5.3 类型
顾名思义, 相对于 ES6, TypeScript 最大的改善是增加了类型系统。有些人可能会觉得,缺乏类型检查正是 JavaScript 这些弱类型语言的优点。 也许你对类型检查心存疑虑, 但我仍然鼓励你试一试。 类型检查的好处有:
- 有助于代码的编写, 因为它可以在编译期预防 bug;
- 有助于代码的阅读, 因为它能清晰地表明你的意图。
另外值得一提的是, TypeScript 中的类型是可选的。 如果希望写一些快速代码或功能原型, 可以首先省略类型, 然后再随着代码日趋成熟逐渐加上类型。
TypeScript的基本类型与我们平时所写JavaScript 代码中用的隐式类型一样, 包括字符串、 数字、 布尔值等。直到 ES5, 我们都在用 var 关键字定义变量, 比如 var name;。TypeScript 的新语法是从 ES5 自然演化而来的, 仍沿用 var 来定义变量,
但现在可以同时为变量名提供可选的变量类型了:
var name: string;
在声明函数时, 也可以为函数参数和返回值指定类型:
function greetText(name: string): string
return "Hello " + name;
这个例子中, 我们定义了一个名为 greetText 的新函数, 它接收一个名为name 的参数。 name: string 语法表示函数想要的 name 参数是 string 类型。 如果给该函数传一个 string 以外的参数, 代码将无法编译通过。 对我们来说, 这是好事, 否则这段代码将会引入 bug。
或许你还注意到了, greetText 函数在括号后面还有一个新语法:string 。冒号之后指定的是该函数的返回值类型, 在本例中为 string。
这很有用, 原因有二:
- 如果不小心让函数返回了一个非 string 型的返回值, 编译器就会告诉我们这里有错误;
- 使用该函数的开发人员也能很清晰地知道自己将会拿到什么类型的数据。
我们来看看如果写了不符合类型声明的代码会怎样
function hello(name: string): string
return 12;
当尝试编译代码时, 将会得到下列错误:
$ tsc compile-error.ts
compile-error.ts(2,12): error TS2322: Type 'number' is not
assignable to type
这是怎么回事? 我们尝试返回一个 number 类型的 12, 但 hello 函数期望的返回值类型为 string(它是在参数声明的后面以): string 的形式声明的) 。要纠正它, 可以把函数的返回值类型改为 number:
function hello(name: string): number
return 12;
虽然这只是一个小例子, 但足以证明类型检查能为我们节省大量调试 bug 的时间。
5.4 内置类型
5.4.1 字符串
字符串包含文本, 声明为 string 类型:
var name: string = 'Tim';
5.4.2 数字
无论整数还是浮点, 任何类型的数字都属于 number 类型。 在 TypeScript中, 所有的数字都是用浮点数表示的, 这些数字的类型就是 number:
var age: number = 36;
5.4.3 布尔类型
布尔类型(boolean) 以 true(真) 和 false(假) 为值。
var married: boolean = true;
5.4.4 数组
数组用 Array 类型表示。 然而, 因为数组是一组相同数据类型的集合,所以我们还需要为数组中的条目指定一个类型。
我们可以用 Array或者 type[]语法来为数组条目指定元素类型:
var jobs: Array<string> = ['IBM', 'Microsoft', 'Google'];
var jobs: string[] = ['Apple', 'Dell', 'HP'];
数字型数组的声明与之类似:
var jobs: Array<number> = [1, 2, 3];
var jobs: number[] = [4, 5, 6];
5.4.5 枚举
枚举是一组可命名数值的集合。 比如, 如果我们想拿到某人的一系列角色, 可以这么写:
enum Role Employee, Manager, Admin;
var role: Role = Role.Employee;
默认情况下, 枚举类型的初始值是 0。 我们也可以调整初始化值的范围:
enum Role Employee = 3, Manager, Admin;
var role: Role = Role.Employee;
在上面的代码中, Employee 的初始值被设置为 3 而不是 0。 枚举中其他项的值是依次递增的, 意味着 Manager 的值为 4, Admin 的值为 5。 同样, 我们也可以单独为枚举中的每一项指定值:
enum Role Employee = 3, Manager = 5, Admin = 7;
var role: Role = Role.Employee;
还可以从枚举的值来反查它的名称:
enum Role Employee, Manager, Admin;
console.log('Roles: ', Role[0], ',', Role[1], 'and',Role[2]);
5.4.6 任意类型
如果我们没有为变量指定类型, 那它的默认类型就是 any。 在 TypeScript中, any 类型的变量能够接收任意类型的数据:
var something: any = 'as string';
something = 1;
something = [1, 2, 3];
5.4.7 “ 无” 类型
void 意味着我们不期望那里有类型。 它通常用作函数的返回值, 表示没有任何返回值:
function setName(name: string): void
this.name = name;
第 6 章 表单
6.1 表单—— 既重要,又复杂
在 Web 应用中, 表单或许是最重要的部分。 虽然我们常从点击链接或移动鼠标中得到事件通知, 但大多数“富数据”都是通过表单从用户那里获得的。
从表面上看, 表单似乎很简单: 创建一个 input 标签, 用户填入数据,然后再点击提交。 这有什么难的?
但事实证明, 表单最终可能是非常复杂的。 原因如下:
-
表单输入意味着需要在页面和服务器端同时修改这份数据;
-
修改的内容通常要在页面的其他地方反映出来;
-
用户的输入可能存在很多问题, 所以需要验证输入的内容;
-
用户界面需要清晰地显示出可能出现的预期结果和错误信息;
-
字段之间的依赖可能存在复杂的业务逻辑;
我们希望不依赖 DOM 选择器就能轻松测试表单。
值得庆幸的是, Angular 已经给出了上述所有问题的解决方案。
- 表单控件(FormControl) 封装了表单中的输入, 并提供了一些可供操
纵的对象。 - 验证器(validator) 让我们能以自己喜欢的任何方式验证表单输入。
- 观察者(observer) 让我们能够监听表单的变化, 并作出相应的回应。
6.2 获取用户输入
当用户点击链接、按下按钮或者输入文字时,这些用户动作都会产生 DOM 事件。 使用 Angular 事件绑定机制来响应任何 DOM 事件。
6.2.1 使用$event
import Component from '@angular/core';
@Component(
selector: 'app-form-basic',
template: `
<div>
<h3>请输入:</h3>
<input type="text" (keyup)="getValue($event)">
<p>values</p>
</div>`
)
export class FormBasicComponent
values = '';
getValue(event: any)
this.values += event.target.value + ' | ';
传入 $event 是靠不住的做法
类型化事件对象揭露了重要的一点,即反对把整个 DOM 事件传到方法中,因为
这样组件会知道太多模板的信息。只有当它知道更多它本不应了解的 HTML 实
现细节时,它才能提取信息。 这就违反了模板(用户看到的)和组件(应用如
何处理用户数据)之间的分离关注原则。
6.2.2 量 使用模板变量 #var
使用 Angular 的模板引用变量。 这些变量提供了从模块中直接访问元素的能力。 在标识符前加上井号 (#) 就能声明一个模板引用变量。
下面的例子使用了局部模板变量,在一个超简单的模板中实现按键反馈功能。
<div>
<h3>请输入:</h3>
<input type="text" #box (keyup)="1">
<p>box.value</p>
</div>
本例代码将 keyup 事件绑定到了数字 0,这是可能是最短的模板语句。 虽然这个语句不做什么,但它满足 Angular 的要求,所以 Angular 将更新屏幕。
6.2.3 事件修饰符
<div>
<h3>请输入:</h3>
<input type="text" #box (keyup.enter)="onEnter(box.value)">
<p>values</p>
</div>
onEnter(value)
this.values += value + ' | ';
(keyup)事件处理器监听每一次按键。 有时只在意回车键,因为它标志着用户结束输入。 解决这个问题的一种方
以上是关于angular5基础笔记的主要内容,如果未能解决你的问题,请参考以下文章
一个基于angular5.0.0+ng-bootstrap 1.0.0-beta版8+bootstrap 4.0.0-beta.2+scs的后台管理系统界面(没基础的同学请先自学基础,谢谢!)