目录

  1. Angular 导学
  2. Angular CLI以及工程结构
  3. Angular componets(组件概览,组件交互,组件生命周期,内容投影)
  4. Angular Module
  5. Angular模板(文本插值,属性绑定,类/样式绑定,事件绑定,双向绑定,模板引用变量)
  6. Angular路由与导航
  7. Angular指令(常用内置指令,属性指令,结构指令)
  8. Angular依赖注入
  9. Angular http模块
  10. Angular从组件生命周期深入到脏值检测(与Vue等其他框架的数据检测更新方案的对比)
  11. Angular表单

    TimeLine

内容 负责人 预计时间
1~3课时 max,zhang 7.23
4~5课时 sun,David 7.30
6~7课时 tiny,Liu 8.9
8~9课时 tiny,Liu 8.16
10课时 max,zhang 8.23
11课时 sun,David 8.31

Angular 导学

前言

这次系列课程会给大家带来angular9基础知识点+实例模拟的内容,
讲解中所有的例子都可以在https://cnnkgapt12.cn.kworld.kpmg.com/mzhang38/my-angular-app中找到,每次课程内容在对应的分支当中。

开始之前请安装angular CLI
npm install -g @angular/cli

Angular优势

框架层面

react/vue:更加针对于视图View层的轻量级类库
Angular: 更能称之为一个框架,模块,组件,服务….等全部都给你提供好了,开箱即用,也就是说你不需要依赖很多三方的开源的类库,不需要去比较这些三方类库的优缺点。
image.png

语言层面

react/vue: 都在拥抱TypeScript,TypeScript已经成为前端的标配,包括VUE3.0 已经使用TS开发,大势所趋
angular:是所有主流框架最早拥抱TS,并且采用TS作为开发语言,提供了大型项目所必须的类型约束。虽然目前react,Vue 都支持TS,但是从集成程度上来看,angular是最友好和最方便的。

生态层面

angular背后两大巨头,谷歌和微软,谷歌很好理解,因为angular就是谷歌团队开发的嘛。然而angular有两大底层建筑是微软提供的,TypeScript 和 Rxjs 。背靠两大巨头,生态基础非常可靠。
A2.jpg

项目层面

  1. 大型项目非常复杂的逻辑,处理这些逻辑大多数都是异步操作,然而angular 深度集成了Rxjs,用Rxjs来处理对于逻辑和异步的响应式编程,这种处理使得对于逻辑和异步的处理非常自然简单。
  2. 项目中需要的复杂的表单处理,angular提供了很好的机制让你处理这些复杂表单的约束以及验证
  3. 很好的文件结构和编码规范,这方面angular都提供好了

image.png

Angular CLI以及工程结构

CLI 构建器用来快速构建angular应用

  1. 要想创建、构建或在开发服务器上运行一个新的、基本的 Angular 项目,请到这个新工作区的上级目录中运行下列命令:
  1. ng new my-angular-app
  2. cd my-angular-app
  3. ng serve

工程结构

  1. workspace configuration files

a3.jpg

工作区配置文件 用途
.editorconfig 代码编辑器的配置文件
.gitignore 指定 Git 应忽略的不必追踪的文件。
README.md 根应用的简介文档.
angular.json CLI 要用到的构建、启动开发服务器和测试工具的配置项。
package.json 配置工作区中所有项目可用的 npm 包依赖
package-lock.json 提供 npm 客户端安装到 node_modules 的所有软件包的版本信息。
src/ 根项目的源文件。
node_modules/ 为整个工作区提供 npm 包
tsconfig.json 工作区中所有项目的基本 TypeScript 配置。所有其它配置文件都继承自这个基本配置。
tslint.json 工作区中所有项目的默认的 TSLint 配置。
  1. application source file

a4.jpg

应用支持文件 目的
app/ 包含定义应用逻辑和数据的组件文件
assets/ 静态资源文件。
environments/ 包含特定目标环境的构建配置选项。默认情况下,有一个无名的标准开发环境和一个生产(“prod”)环境。你还可以定义其它的目标环境配置。
favicon.ico 用作该应用在标签栏中的图标。
index.html 当有人访问你的站点时,提供服务的主要 HTML 页面。CLI 会在构建你的应用时自动添加所有的 JavaScript 和 CSS 文件
main.ts 应用的主要切入点
polyfills.ts 为浏览器支持提供了polyfill脚本。
styles.less 列出为项目提供样式的 CSS 文件。该扩展还反映了你为该项目配置的样式预处理器。
test.ts 单元测试的主入口点,带有一些 Angular 特有的配置。你通常不需要编辑这个文件。

Angular Components

  1. 组件长什么样子?
  2. 如何创建组件?
  3. 组件生命周期?
  4. 组件之间的数据交互方式?
  5. 怎么实现组件投影?

组件长什么样子?

  • 文件结构

截屏2021-07-18 上午11.09.42.png

  • html&css文件大家都比较熟悉了,我们着重看一下xxxx.component.ts文件结构,以app.compontent.ts 为例
  1. import { Component } from '@angular/core';
  2. @Component({
  3. selector: 'app-root', //这个 CSS 选择器用于在模板中标记出该指令,并触发该指令的实例化
  4. templateUrl: './app.component.html',//Angular 组件模板文件的 URL
  5. styleUrls: ['./app.component.less']//一个或多个 URL,指向包含本组件 CSS 样式表的文件
  6. })
  7. export class AppComponent {
  8. title = 'my-angular-app';
  9. }
  1. @Compont:这是一个组件装饰器,用于把某个类标记为 Angular 组件,并为它配置一些元数据,以决定该组件在运行期间该如何处理、实例化和使用。类似于Java里的注解,angular有很多的装饰器,他将元数据添加到类、类成员(属性、方法)和函数参数上。(要了解更多可以去看下TypeScript装饰器原理),以上是常用元数据属性,还有很多属性类似changeDetection/animations可以自行翻阅官网API

如何创建组件?

  1. 手动创建
  2. 使用angular CLI 创建??可以在命令行中使用 ng generate 命令往该应用中添加功能,组件和数据???请课后自行研究一下

    组件的生命周期

截屏2021-07-18 下午3.01.37.png
可知常用钩子执行顺序如上

截屏2021-07-18 下午3.13.15.png
可知:

钩子方法 用途 时机
ngOnChanges() 当组件设置或重新设置数据绑定的输入属性时响应。 该方法接受当前和上一属性值的 [SimpleChanges](https://angular.cn/api/core/SimpleChanges) 对象
注意,这发生的非常频繁,所以你在这里执行的任何操作都会显著影响性能。
ngOnInit() 之前以及所绑定的一个或多个输入属性的值发生变化时都会调用。
注意,如果你的组件没有输入,或者你使用它时没有提供任何输入,那么框架就不会调用 ngOnChanges()
ngOnInit() 在组件第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件 在第一轮 ngOnChanges() 完成之后调用,只调用一次
ngDoCheck() 发生脏值检测时会调用的钩子 紧跟在每次执行变更检测时的 ngOnChanges() 和 首次执行变更检测时的 ngOnInit() 后调用。
  • 浅谈Dngular变更检测
  1. 变更检测的作用—— 如果组件属性被改变,检测组件模版上的所有绑定关系,与其绑定的模版相应区域可能需要更新的过程。类似于VUE里的数据劫持,react中的Fiber
  2. 何时执行——异步事件(用户输入操作,比如点击,提交等,请求服务端数据,定时事件等可能改变绑定属性的操作)
  3. ngOnchange()和ngDocheck()有何不同
    1. demo的多次点击change按钮可知,一旦执行变更检测必定会调用ngDoCheck(),而ngOnchange()是执行变更检测后属性值发生变化时候才会调用
    2. ngOnchange()无法检测到应用类型值的变化,而ngDoCheck()可以(见https://cnnkgapt12.cn.kworld.kpmg.com/mzhang38/my-angular-app/tree/SESSION1/src/app/lifecycle点击change list)
ngAfterContentInit() 当 Angular 把外部内容投影进组件视图或指令所在的视图之后调用。 第一次 ngDoCheck() 之后调用,只调用一次。
ngAfterContentChecked() 每当 Angular 检查完被投影到组件或指令中的内容之后调用。 ngAfterContentInit() 和每次 ngDoCheck() 之后调用
ngAfterViewInit() 当 Angular 初始化完组件视图及其子视图或包含该指令的视图之后调用。 第一次 ngAfterContentChecked() 之后调用,只调用一次。
ngAfterViewChecked() 每当 Angular 做完组件视图和子视图或包含该指令的视图的变更检测之后调用。 ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。
ngOnDestroy() 每当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。 在 Angular 销毁指令或组件之前立即调用。
  • 带check的生命周期和doCheck类似都是变更检测时执行
  • ngAfterContentInit()和ngAfterViewInit() 需要注意需要操作组件视图实例时候,需要在此或之后获取。

组件间的数据交互

  1. 通过输入性属性把数据从父组件传递给子组件,@Input()装饰器
  2. 通过setter截听输入属性的变化
  3. 父组件监听子组件的事件(demo中父组件如何获取子组件输入的变化??)
    1. 子组件暴露一个 [EventEmitter](https://angular.cn/api/core/EventEmitter) 属性,当事件发生时,子组件利用该属性 emits(向上发布)事件。父组件绑定到这个事件属性,并在事件发生时作出回应。
    2. 子组件的 [EventEmitter](https://angular.cn/api/core/EventEmitter) 属性是一个输出属性,通常带有@Output 装饰器 ```typescript import {Component, Input, Output, EventEmitter} from ‘@angular/core’;

@Component({ selector: ‘setter-demo’, templateUrl: ‘./setter.component.html’ }) export class SetterComponent { /**

  1. * @Input()装饰器定义输入属性,通过输入性属性把数据从父组件传递给子组件
  2. * */
  3. @Input()
  4. /**
  5. * 通过setter截听输入属性的变化
  6. * */
  7. set name(name: string) {
  8. this._name = name.toUpperCase();
  9. }
  10. get name(): string {
  11. return this._name;
  12. }
  13. private _name = '';
  14. /**
  15. * @Output()装饰器暴露一个EventEmitter属性,父组件绑定此事件属性定义回应方法
  16. * */
  17. @Output() inputChange = new EventEmitter<string>();
  18. constructor() {
  19. }
  20. change($event: string) {
  21. console.log($event)
  22. /**
  23. * @子组件利用inputChange.emit(向上发布)事件
  24. * */
  25. //this.inputChange.emit(this.name)
  26. }

}

  1. 4. 封装一个input类型组件,如何实现双向数据绑定
  2. ```typescript
  3. import {Component, Input, Output, EventEmitter, OnInit} from '@angular/core';
  4. @Component({
  5. selector: 'my-input-demo',
  6. templateUrl: './my-input.component.html'
  7. })
  8. export class MyInputComponent implements OnInit {
  9. @Input() value = ''
  10. /**
  11. * angular中约定@input()属性名+change 定义@output EventEmitter属性名,即可在调用时实现[(value)]的双向绑定写法
  12. * */
  13. @Output() valueChange = new EventEmitter<string>();
  14. options: any[] = []
  15. change($event: string) {
  16. this.valueChange.emit($event)
  17. }
  18. ngOnInit() {
  19. const that = this
  20. setTimeout(() => {
  21. this.options = [
  22. {id: '1', name: 'Max'},
  23. {id: '2', name: 'Tiny'},
  24. {id: '3', name: 'David'},
  25. ]
  26. }, 100)
  27. }
  28. }
  1. 父组件通过@ViewChild获取子组件访问权
  2. 通过依赖注入service共享数据(后面章节讲依赖注入时候会讲解) ```typescript import {Component, ViewChild} from ‘@angular/core’; import {ViewChildComponent} from “../viewChild/view-child.component”;

@Component({ selector: ‘main-demo’, templateUrl: ‘./main.component.html’, styleUrls: [‘./main.component.less’] }) export class MainComponent { title = ‘my-angular-app’; name = ‘kpmg’

  1. /**父组件通过@ViewChild获取子组件访问权
  2. *
  3. * 任何带有 @Component 或 @Directive 装饰器的类
  4. *
  5. * 字符串形式的模板引用变量(比如可以使用 @ViewChild('cmp') 来查询 <my-component #cmp></my-component>
  6. *
  7. * 组件树中任何当前组件的子组件所定义的提供者(比如 @ViewChild(SomeService) someService: SomeService )
  8. *
  9. * TemplateRef(比如可以用 @ViewChild(TemplateRef) template; 来查询 <ng-template></ng-template>)
  10. * */
  11. @ViewChild(ViewChildComponent)
  12. private childComponent!: ViewChildComponent;//非空断言
  13. constructor() {
  14. }
  15. inputChange($event: string) {
  16. this.name = $event
  17. }
  18. start() {
  19. this.childComponent.start();
  20. }
  21. stop() {
  22. this.childComponent.stop();
  23. }

}

  1. <a name="NXIrS"></a>
  2. #### 组件内容投影
  3. 1. 使用<ng-content>实现内容映射
  4. 1. `ngTemplateOutlet` 指令来渲染给定的 `ng-template` 元素,ng-template是Angular 结构型指令中的一种,用于定义模板。定义的模板不会直接显示出来,需要通过其他结构型指令(如 ng-if)将模块内容渲染到页面中。
  5. 1. <ng-content><ng-template> 区别:`ng-template` 元素,你可以让组件根据你想要的任何条件显式渲染内容,并可以进行多次渲染。在显式渲染 `ng-template` 元素之前,Angular 不会初始化该元素的内容。
  6. ```typescript
  7. <div>
  8. <div class="header" *ngIf="template;else header">
  9. <!--ngTemplateOutlet 指令来渲染给定的 传入ng-template 元素-->
  10. <ng-container *ngTemplateOutlet="template"></ng-container>
  11. </div>
  12. <ng-template #header>
  13. <div class="header">
  14. 默认的header
  15. </div>
  16. </ng-template>
  17. <div class="content">
  18. <label>content</label>
  19. <!--使用ng-content 接收映射内容-->
  20. <ng-content>
  21. </ng-content>
  22. </div>
  23. <div class="footer">
  24. <label>footer</label>
  25. <!--使用ng-content select 属性实现多插槽内容投影-->
  26. <ng-content select="[footer]"></ng-content>
  27. </div>
  28. </div>
  29. import {Component, Input, TemplateRef} from '@angular/core';
  30. @Component({
  31. selector: 'template-outlet-demo',
  32. templateUrl: './template-outlet.component.html',
  33. styleUrls: ['./template-outlet.component.less']
  34. })
  35. export class TemplateOutletComponent {
  36. /**
  37. * 传入谁属性不只是string,number等常用类型,也可以是一个TemplateRef 类型
  38. * */
  39. @Input() template!: TemplateRef<void>;
  40. }
  41. <h1>内容投影 demo</h1>
  42. <template-outlet-demo>
  43. <my-input-demo [(value)]="user"></my-input-demo>
  44. </template-outlet-demo>
  45. <br><br><br><br><br><br><br><br>
  46. <h1>多个内容投影 demo</h1>
  47. <template-outlet-demo>
  48. <my-input-demo [(value)]="user"></my-input-demo>
  49. <div footer>footer 投影内容</div>
  50. </template-outlet-demo>
  51. <br><br><br><br><br><br><br><br>
  52. <h1>ngTemplateOutlet demo</h1>
  53. <template-outlet-demo [template]="header"></template-outlet-demo>
  54. <ng-template #header>
  55. <a>这里是自定义header</a>
  56. </ng-template>

???实现一个下面的input 组件 ,右部可以自定义传入自定义的模板或者文字。
Annotation 2021-07-23 140028.jpg