学习网站: 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 如果在组件上声明变量,该变量就会引用该组件实例。

如果在标准的 HTML 标记上声明变量,该变量就会引用该元素。

如果你在 <ng-template> 元素上声明变量,该变量就会引用一个 TemplateRef 实例来代表此模板。

如果该变量在右侧指定了一个名字,比如 #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  哈哈哈~_~  阅读(150)  评论(0)    收藏  举报