学习网站: https://www.bookstack.cn/read/Angular2-Training-Book/README.md

Angular 正确使用 @ViewChild、@ViewChildren 访问 DOM、组件、指令

在Angular中自定义Webpack配置

angular2+ 利用FactoryProvider和APP_INITIALIZER初始化项目配置

达观数据:Angular 6+依赖注入使用指南:providedIn与providers对比

Angular HttpInterceptor拦截器 多情景应用

angular中的背景图片处理

copyfiles在编译打包时的用法

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

ng-packagr 默认会根据 package.json 的 peerDependencies 节点清单来决定类库所需要第三方依赖包,这些依赖包是不会被打包至类库。
然而,所依赖包不存在 peerDependencies 节点里时(当然建议需要依赖的项应该在里面),就需要该属性的配置。

lib/entryFile

指定入口文件。

lib/umdModuleIds

UMD 格式采用 rollup 打包,当类库需要引用一些无法猜出正确 UMD 标识符时,就需要你手动映射这些类库的标识。
"umdModuleIds": {
  "lodash": "_"
}

配置package.json

dependencies

会被构建打包到最终的产物中

devDependencies

仅开发环境会使用到,不会被打包到最终的产物中

peerDependencies

放宿主环境和插件都需要依赖的包,避免重复下载。
更多的是在公共库或者三方插件中使用,平时的开发中几乎不会使用
 

配置tsconfig.json

  1. compilerOptions:编译器相关的选项。比如配置编译成 ES5,模块化使用 commonjs 等。这里的编译配置很多,后面我们会讲解一些常用的配置;
  2. files:指定需要被编译的文件列表。这里不能指定目录,只能是文件,可以省略 .ts 后缀。适合需要编译的文件比较少的情况。默认值为 false;
  3. include:指定需要编译的文件列表或匹配模式。include 可以通过通配符指定目录,如 "src/**/*" 表示 src 下的所有文件。如果没有指定 files 配置,默认值为 ** ,即项目下所有文件;如果配置了 files,默认值为 [] 空数组;
  4. exclude:在 include 圈定的范围内,排除掉一些文件。我们经常用它来排除编译输出目录、测试文件目录、一些生成文件的脚本等文件。默认值为 "node_modules,bower_componen";
  5. extends:继承另一个 ts 配置文件。这在 monorepo 的代码组织中非常有用,不同的 package 可以通过 extends 继承通用的 ts 配置。用法示例:"extends": "./common-tsconfig.json"。
  6. reference:引用。项目中如果有多个相互独立的模块,可以使用这个属性来做分离。这样一个模块改变后,就只重新编译这个模块,其他模块不重新编译。编译时要改用 tsc --build。这在非常大的项目中应该能有不小收益。

需要注意的是,files、include、exclude 只是指定编译的入口文件范围,如果其中的文件 import 了范围外的 ts 文件,范围外的文件依旧会被编译。


 

angular.json参数详解

https://blog.csdn.net/weixin_34413802/article/details/88733424?spm=1001.2101.3001.6650.2&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-88733424-blog-121747144.235%5Ev43%5Epc_blog_bottom_relevance_base6&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-2-88733424-blog-121747144.235%5Ev43%5Epc_blog_bottom_relevance_base6&utm_relevant_index=5
posted on 2021-11-30 11:58  哈哈哈~_~  阅读(181)  评论(0)    收藏  举报