学习网站: https://www.bookstack.cn/read/Angular2-Training-Book/README.md
Angular 正确使用 @ViewChild、@ViewChildren 访问 DOM、组件、指令
angular2+ 利用FactoryProvider和APP_INITIALIZER初始化项目配置
达观数据:Angular 6+依赖注入使用指南:providedIn与providers对比
Angular HttpInterceptor拦截器 多情景应用
Angular之ng-template,ng-content,ng-container,* ngTemplateOutlet
关于Angular CLI
Angular CLI又称 Angular脚手架,用于快速生成项目或者组件的框架以提高效率。可以方便的生成angular app、component、service 等等, 并且可以通过参数,按照自己的需求去创建。可以说是angular开发必不可少的利器。
ng generate: 新建component、service、pipe, class 等
ng new: 新建angular app
ng update: 升级angular自身,以及依赖
ng version: 显示anuglar cli全局版本、以及本地的angular cli、angular code等的版本
ng add: 新增第三方库。会做2件事,1)基于npm安装node_modules, 2)自动更改配置文件,保证新的依赖正常工作
什么是Angular
Angular 是一个基于 TypeScript 构建的开发平台。它包括:
一个基于组件的框架,用于构建可伸缩的 Web 应用
一组完美集成的库,涵盖各种功能,包括路由、表单管理、客户端-服务器通信等
一套开发工具,可帮助你开发、构建、测试和更新代码
Angular常用
组件
组件是 Angular 应用的主要构造块
一个 HTML 模板,用于声明页面要渲染的内容
一个用于定义行为的 Typescript 类
一个 CSS 选择器,用于定义组件在模板中的使用方式
每个组件都需要一个 CSS 选择器。选择器会告诉 Angular:当在模板 HTML 中找到相应的标签时,就把该组件实例化在那里。
(可选)要应用在模板上的 CSS 样式
生命周期
当你的应用通过调用构造函数来实例化一个组件或指令时,Angular 就会调用那个在该实例生命周期的适当位置实现了的那些钩子方法
|
钩子方法 |
用途 |
时机 |
|
ngOnChanges() |
当 Angular 设置或重新设置数据绑定的输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象 注意,这发生的非常频繁,所以你在这里执行的任何操作都会显著影响性能。 |
如果组件绑定过输入属性,那么在 ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。 注意,如果你的组件没有输入属性,或者你使用它时没有提供任何输入属性,那么框架就不会调用 ngOnChanges()。 |
|
ngOnInit() |
在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。 |
在第一轮 ngOnChanges() 完成之后调用,只调用一次。而且即使没有调用过 ngOnChanges(),也仍然会调用 ngOnInit()(比如当模板中没有绑定任何输入属性时)。 |
|
ngDoCheck() |
检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。 |
紧跟在每次执行变更检测时的 ngOnChanges() 和 首次执行变更检测时的 ngOnInit() 后调用。 |
|
ngAfterContentInit() |
当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。 |
第一次 ngDoCheck() 之后调用,只调用一次。 |
|
ngAfterContentChecked() |
每当 Angular 检查完被投影到组件或指令中的内容之后调用。 |
ngAfterContentInit() 和每次 ngDoCheck() 之后调用 |
|
ngAfterViewInit() |
当 Angular 初始化完组件视图及其子视图或包含该指令的视图之后调用。 |
第一次 ngAfterContentChecked() 之后调用,只调用一次。 |
|
ngAfterViewChecked() |
每当 Angular 做完组件视图和子视图或包含该指令的视图的变更检测之后调用。 |
ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。 |
|
ngOnDestroy() |
每当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。 也可以用来通知应用程序的其它部分,该组件即将消失 |
|
模板
模板是一段 HTML,它告诉 Angular 如何在应用中渲染组件
为了消除脚本注入攻击的风险,Angular 不支持模板中使用 <script> 元素。Angular 会忽略 <script> 标记,并向浏览器控制台输出一条警告。
模板变量
模板变量可以帮助你在模板的另一部分使用这个部分的数据
使用井号 # 来声明一个模板变量
l 如果在组件上声明变量,该变量就会引用该组件实例。
l 如果在标准的 HTML 标记上声明变量,该变量就会引用该元素。
l 如果你在 <ng-template> 元素上声明变量,该变量就会引用一个 TemplateRef 实例来代表此模板。
l 如果该变量在右侧指定了一个名字,比如 #var="ngModel" ,那么该变量就会引用所在元素上具有这个 exportAs 名字的指令或组件。--为了精确定位索要引用的
@Directive({
selector: '[lib-plupload]',
exportAs: 'plupload',
})
<button type="button" nz-button [nzType]="'primary'" #pickfileButton=plupload lib-plupload>
<i nz-icon nzType="upload"></i>
<span>上传附件</span>
</button>
下面的例子就使用了模板输入变量 customer。
content_copy
<ul>
<li *ngFor="let customer of customers">{{customer.name}}</li>
</ul>
接下来的例子使用了模板引用变量 #customerInput。
<label>Type something:
<input #customerInput>{{customerInput.value}}
</label>
单向绑定
1属性绑定:在单一方向上将值从组件的属性送到目标元素的属性。
<img [src]="itemImageUrl">
2 事件绑定:可以侦听并响应用户操作,例如按键、鼠标移动、点击和触摸
<button (click)="onSave()">Save</button>
3 插值绑定:将在相应的组件模板中显示变量的值。
通过插值,你可以动态更改应用视图中显示的内容,使用双花括号 {{ 和 }} 作为定界符
<h3>Current customer: {{ currentCustomer }}</h3>
双向绑定
双向绑定为应用中的组件提供了一种共享数据的方式。
使用双向绑定绑定来侦听事件并在父组件和子组件之间同步更新值。
比如: nz-zorro很多组件使用ngModel,使用双向绑定的话,值就同步更新了,就不需要再写事件绑定去接受子组件传过来的值了
Angular 的双向绑定语法是方括号和圆括号的组合,[] 进行属性绑定,() 进行事件绑定
指令
指令是为 Angular 应用程序中的元素添加额外行为的类。
组件 —— 带有模板的指令。这种指令类型是最常见的指令类型
属性型指令 —— 更改元素、组件或其他指令的外观或行为的指令。
结构型指令 —— 通过添加和删除 DOM 元素来更改 DOM 布局的指令
内置属性型指令
属性型指令会监听并修改其它 HTML 元素和组件的行为、Attribute 和 Property。
NgClass —— 添加和删除一组 CSS 类。
要添加或删除单个类,请使用类绑定 [class.sale]="onSale"
NgStyle —— 添加和删除一组 HTML 样式。
单一样式绑定 [style.width]="width"
NgModel —— 将数据双向绑定添加到 HTML 表单元素。
内置结构型指令
结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的结构,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。
本节会介绍最常见的内置结构型指令:
NgIf —— 从模板中创建或销毁子视图。
NgFor —— 为列表中的每个条目重复渲染一个节点。
使用 *ngFor 的 trackBy 属性,Angular 只能更改和重新渲染已更改的条目,而不必重新加载整个条目列表。
NgSwitch —— 一组在备用视图之间切换的指令。
依赖注入
依赖项注入(DI)是一种设计模式,在这种设计模式中,类会从外部源请求依赖项而不是创建它们。
在 Angular 中,依赖项是指某个类执行其功能所需的服务或对象。
依赖通常是服务,但是也可以是值,比如字符串或函数。
应用的注入器(它是在启动期间自动创建的)会使用该服务或值的配置好的提供者来按需实例化这些依赖。各个不同的提供者可以为同一个服务提供不同的实现
具体来说:当 Angular 创建组件类的新实例时,通过查看该组件类的构造函数,来为该组件提供依赖
1首先检查是否该注入器中已经有了那个服务的任何现有实例。
2如果所请求的服务尚不存在,注入器就会使用以前注册的服务提供者来制作一个,并把它加入注入器中
注入器是主要的机制。Angular 会在启动过程中为你创建全应用级注入器以及所需的其它注入器。
不用自己创建注入器。该注入器会创建依赖、维护一个容器来管理这些依赖,并尽可能复用它们。
提供者是一个对象,用来告诉注入器应该如何获取或创建依赖
@Injectable() 装饰器会指定 Angular 可以在 DI 体系中使用此类。
默认情况下,Angular CLI 的 ng generate service 命令会在 @Injectable() 装饰器中提供元数据来把它注册到根注入器中
根:提供服务时,Angular 会为 HeroService 创建一个单一的共享实例,并且把它注入到任何想要它的类中
元数据 providedIn: 'root' 表示 HeroService 在整个应用程序中都是可见的。
模块级别:当在 NgModule 注册提供者时,该服务的同一个实例将会对该 NgModule 中的所有组件可用。
要想在这一层注册,请用 @NgModule() 装饰器中的 providers 属性
组件级别:当你在组件级注册提供者时,你会为该组件的每一个新实例提供该服务的一个新实例。
要在组件级注册,就要在 @Component() 元数据的 providers 属性中注册服务提供者。
什么是Angular Injector
Injector,注入器。主要工作是负责向服务与组件、指令等注入依赖。
Injector主要通过Angular provider中的token进行查找需要注入的依赖。
Angular Provider中提供了依赖的相关信息,比如token,创建实例的方式等。
Injector通过这些信息进行创建实例,并负责把实例注入到服务、组件、指令中。
什么时候创建Angular Injector
首先,在根模块启动的时候会创建一个注入器,此时这个注入器作用于全局。整个应用会创建一棵组件树,appcomponent为根组件。同样,injector也会配合创建注入器树,为每个组件维护需要注入的内容。
怎么注册需要注入的依赖
可以使用Providers,具体使用provide:[Aservice,Bservice],复杂一点的如providers:[{provide:xxx,useValue:xxx}],还可以useClass,useFactory,以及depths等。这里不再具体展开。
@Injectable
@Injectable装饰器是告诉Angular框架,这个服务或者组件的构造函数的参数需要依赖注入器进行注入。所以如果构造函数中没有参数,可以无需@Injectable装饰器。
组件和指令为什么没有@Injetable也能注入构造函数中的参数?因为@Component和@Directive装饰器也具备告知框架构造函数参数需要依赖注入,所以无需再组件、指令中使用@Injectable装饰器。
@Inject
@Inject是构造函数参数的注入器。@Inject(token) private ualue:ValueType,它告诉Angular框架需要从注入器中获取token对应的一个实例进行注入。
所以如果我们在一个服务中的构造函数中依赖注入参数,也可以不使用@Injectable装饰器,可以直接在参数中使用@Inject(Aservice) private aService: Aservice进行注入。
路由
在单页应用中,通过显示或隐藏组件来更改用户看到的内容,而不用去服务器获取新页面。
要处理从一个视图到下一个视图的导航,Router 会通过将浏览器 URL 解释为更改视图的操作指令来启用导航。
带路由的 Angular 应用中有一个 Router 服务的单例实例
可以从任何地方使用应用的 Router 服务和 routerState 属性来访问当前的 RouterState
路由原理
HTML 5的history.pushState history.replaceState,改变浏览器的当前地址和历史,却又不会触发服务端页面请求。
angular-cli里默认使用的是HTML5 History 模式
表单
Angular 提供了两种不同的方法来通过表单处理用户输入:响应式表单和模板驱动表单
都建立在下列基础类之上:
FormControl 实例用于追踪单个表单控件的值和验证状态。
FormGroup 用于追踪一个表单控件组的值和状态。
FormArray 用于追踪表单控件数组的值和状态。
ControlValueAccessor 用于在 Angular 的 FormControl 实例和内置 DOM 元素之间创建一个桥梁。
关键差异
|
|
响应式 |
模板驱动 |
|
建立表单模型 |
显式的,在组件类中创建 |
隐式的,由指令创建 |
|
数据模型 |
结构化和不可变的 |
非结构化和可变的 |
|
数据流 |
同步 |
异步 |
|
表单验证 |
函数 |
指令 |
|
适用于 |
大型表单 可复用性高 |
简单表单 可复用性低 |
Angular 提供了两种方式来编译你的应用:
即时编译 (JIT),它会在运行期间在浏览器中编译你的应用。这是 Angular 8 及更早版本的默认值。
预先(AOT)编译,它会在构建时编译你的应用和库。这是 Angular 9 及后续版本的默认值。
Angular 应用主要由组件及其 HTML 模板组成。由于浏览器无法直接理解 Angular 所提供的组件和模板,因此 Angular 应用程序需要先进行编译才能在浏览器中运行。
在浏览器下载和运行代码之前的编译阶段,Angular 预先(AOT)编译器会先把你的 Angular HTML 和 TypeScript 代码转换成高效的 JavaScript 代码。 在构建期间编译应用可以让浏览器中的渲染更快速。
使用 AOT 的部分原因。
更快的渲染。 借助 AOT,浏览器可以下载应用的预编译版本。浏览器加载的是可执行代码,因此它可以立即渲染应用,而无需等待先编译好应用。
更少的异步请求。 编译器会在应用 JavaScript 中内联外部 HTML 模板和 CSS 样式表,从而消除了对那些源文件的单独 ajax 请求。
较小的 Angular 框架下载大小。 如果已编译应用程序,则无需下载 Angular 编译器。编译器大约是 Angular 本身的一半,因此省略编译器会大大减少应用程序的有效载荷。
尽早检测模板错误。 AOT 编译器会在构建步骤中检测并报告模板绑定错误,然后用户才能看到它们。
更高的安全性。 AOT 在将 HTML 模板和组件提供给客户端之前就将其编译为 JavaScript 文件。没有要读取的模板,没有潜藏风险的客户端 HTML 或 JavaScript eval,受到注入攻击的机会就更少了。
angular一些用法
自定义pipe
import { PipeTransform, Pipe } from '@angular/core';
import { CurrencyPipe } from '@angular/common';
/**
* 内置 `_currency` 货币格式化 https://angular.cn/api/common/CurrencyPipe
*/
@Pipe({ name: '_currency' })
export class CNCurrencyPipe extends CurrencyPipe implements PipeTransform {
transform(
value: any,
currencyCode: string = '¥',
display: 'code' | 'symbol' | 'symbol-narrow' | boolean = 'code',
digits?: string
): string | null {
return super.transform(value, currencyCode, <any>display, digits);
}
}
参数传递。使用冒号传递
<div> {{data.budget | _currency: ' ': 'code': '1.0-2'}}</div>
<nz-input-number formControlName="ApprovedFund" [nzMin]="0" [nzMax]="99999999" [nzStep]="1" [nzPrecision]="2" [nzFormatter]="formatterRMB"></nz-input-number>
formatterRMB = (num: number): string => { const pipe = new CNCurrencyPipe('zh-Hans'); return pipe.transform(num, ' ', 'code', '1.0-2'); // ' '表示不显示¥ };
父子组件通信,@Host和forwardRef
一个AppComponent,其模板创建一个导航栏,其导航项会在其ngOnInit上读入AppComponent的公共变量(称为"项")。 * ngfor然后渲染项目。一切正常。
AppComponent模板的底部是一个div,在其中放置了一个路由器插座。取决于用户选择路线的导航项,将触发并呈现不同的子组件。
在这些子组件之一中,我需要在父AppComponent中引用变量" items"。将AppComponent传递给其构造函数中的SubComponent的三种方法:
1. constructor(@Host() _host: AppComponent) // 不行 2. constructor(@Inject(forwardRef(() => AppComponent)) _host) 3. constructor(@Host() @Inject(forwardRef(() => AppComponent)) _host)
使用ng-packagr打包Angular的方法示例
https://www.mianshigee.com/note/detail/67445swj/
whitelistedNonPeerDependencies
lib/entryFile
指定入口文件。
lib/umdModuleIds
配置package.json
dependencies
会被构建打包到最终的产物中
devDependencies
仅开发环境会使用到,不会被打包到最终的产物中
peerDependencies
配置tsconfig.json
- compilerOptions:编译器相关的选项。比如配置编译成 ES5,模块化使用 commonjs 等。这里的编译配置很多,后面我们会讲解一些常用的配置;
- files:指定需要被编译的文件列表。这里不能指定目录,只能是文件,可以省略
.ts后缀。适合需要编译的文件比较少的情况。默认值为 false; - include:指定需要编译的文件列表或匹配模式。include 可以通过通配符指定目录,如
"src/**/*"表示 src 下的所有文件。如果没有指定 files 配置,默认值为**,即项目下所有文件;如果配置了 files,默认值为[]空数组; - exclude:在 include 圈定的范围内,排除掉一些文件。我们经常用它来排除编译输出目录、测试文件目录、一些生成文件的脚本等文件。默认值为 "node_modules,bower_componen";
- extends:继承另一个 ts 配置文件。这在 monorepo 的代码组织中非常有用,不同的 package 可以通过 extends 继承通用的 ts 配置。用法示例:
"extends": "./common-tsconfig.json"。 - reference:引用。项目中如果有多个相互独立的模块,可以使用这个属性来做分离。这样一个模块改变后,就只重新编译这个模块,其他模块不重新编译。编译时要改用
tsc --build。这在非常大的项目中应该能有不小收益。
需要注意的是,files、include、exclude 只是指定编译的入口文件范围,如果其中的文件 import 了范围外的 ts 文件,范围外的文件依旧会被编译。
浙公网安备 33010602011771号