Angular 复习与进阶系列 – Component 组件 の Lifecycle Hooks
前言
我们在 这篇 和 这篇 中已经学习了几个基本的 Lifecycle Hooks. 分别是
constructor
OnInit
AfterContentInit
AfterViewInit
OnDestroy
OnChanges
这篇我们会把其余的 Lifecycle Hooks 都学完.
Init Group and Changes Group
Angular 的 Lifecycle 可以分为两组.
第一组有 constructor, OnInit, AfterContentInit, AfterViewInit, OnDestroy
第二组有 OnChanges, DoCheck, AfterContentChecked, AfterViewChecked
在 first time render 时, 上面两组都会跑. 但绝大部分情况下我们关心第一组就可以了.
而在 event 发生后, 我们更多的是会用到第二组.
所以我喜欢把它们分开两组看待.
Init Group Lifecycle Hooks (组件内视角)
在一个组件内部观察的话, Lifecycle Hooks 的顺序是这样的
constructor > OnInit > AfterContentInit > AfterViewInit > OnDestroy
下面我讲一下各个 hook 的特点
constructor
1. 这个阶段 @Input 还没有被赋值, 都是 undefined.
2. 这个阶段 inject parent 已经拿到组件实例了, 但这个实例的 @Input 也是 undefined.
3. 这个阶段 query child 是连组件实例都没有的. 空空如也
4. 这个阶段, 组件 template 还没有 append 到 document
OnInit
1. 这个阶段 @Input 已经有值了.
2. 通常我们会在这个阶段去 ajax 什么的, 大部分代码都会写在这个阶段里.
3. 如果 @ViewChild / @ContentChild 配置 option static : true, 那么这个阶段已经可以拿到组件实例了, 但是这个组件是还没有 OnInit 的 (它的 @Input 都是 undefined)
4. 这个阶段组件 template 已经 append 到 document 了, 但是涉及 binding 的部分都没有 render 好 (empty)
AfterContentInit
1. 这个阶段 @ContentChild 已经可以拿到组件实例了, 而且这个组件已经 OnInit 好了 (但还没有 AfterViewInit 哦)
AfterViewInit
1. 这个阶段组件 template binding 的部分都 render 好了.
2. 通常这个阶段我们可以去 read DOM dimension, 比如 window.getComputedStyle 之类的
3. 这个阶段我们不应该再去修改 view model 了, 如果要修改那样配上 requestAnimationFrame, 让 Angular 进入下一个渲染周期 (这个是 Change Detection 概念, 这里不过多展开)
OnDestroy
1. 这个阶段 DOM 已经被移除了.
2. 通常我们在这个阶段释放资源, 比如 RxJS unsubscribe 等等.
Init Group Lifecycle Hooks (组件外视角)
上一 part 我们是站在一个组件内的视角去看 lifecycle hooks. 现在我们从外部看多个组件它们 lifecycle hooks 的顺序是怎样的.
首先我们有 5 个组件
App, Child, InsideChild, TranscludeToChild, InsideTranscludeToChild
all html
<!-- app.html --> <app-child> <app-transclude-to-child></app-transclude-to-child> </app-child> <!-- child.html --> <app-inside-child></app-inside-child> <ng-content></ng-content> <!-- inside-child.html --> <p>inside-child works!</p> <!-- transclude-to-child.html --> <app-inside-transclude-to-child></app-inside-transclude-to-child> <!-- inside-transclude-to-child.html --> <p>inside-transclude-to-child works!</p>
source 在这里 Github – repository
先了解组件结构
app > child > inside child 这 3 个就是一层一层进,
transclude-to-child 最特别, app.html 把 transclude-to-child 组件 transclude 到 child 组件.
最后 transclude-to-child > inside-transclude-to-child 就是进一层.
constructor, OnInit, AfterContentInit, AfterViewInit 的顺序.
constructor 环节
第一个环节是 constructor. Angular 会把所有组件都实例化出来先.
1. app constructor
然后进入 app.html
<app-child> <app-transclude-to-child></app-transclude-to-child> </app-child>
接着
2. child constructor
3. transclude to child constructor
接着进入 child.html
<p>child works!</p> <app-inside-child></app-inside-child> <ng-content></ng-content>
4. inside child constructor
进入 inside-child.html
<p>inside-child works!</p>
这里没有组件需要实例化了. 返回最外面 app,html
<app-child> <app-transclude-to-child></app-transclude-to-child> </app-child>
进入 transclude-to-child.html
<p>transclude-to-child works!</p> <app-inside-transclude-to-child></app-inside-transclude-to-child>
5. inside transclude to child constructor
进入 inside-transclude-to-child.html
<p>inside-transclude-to-child works!</p>
没有组件需要实例化了.
至此 constructor 环境结束. 以下是组件 constructor 的 console
OnInit > AfterContentInit > AfterViewInit 环节
和 constructor 不同, Angular 不会先把所有组件 OnInit 一遍才 AfterContentInit. OnInit 和 AfterContentInit 是前脚后脚一起的, 看下面例子理解.
1. app init
<body> <app-root></app-root> </body>
由于 app-root 没有任何的 transclude, 所以 app 组件 AfterContentInit 紧跟着 OnInit 后就触发
2. app after content init
进入 app.html
<app-child> <app-transclude-to-child></app-transclude-to-child> </app-child>
3. child init
由于 child 有 transclude 所以它的 AfterContentInit 不会马上触发.
4. transclude to child init
transclude to child 没有 transclude 所以 AfterContentInit 马上触发
5. transclude to child after content init
此时 child 的 transclude 完成了, 所以到它的 after content init
6. child after content init
进入 child.html
<p>child works!</p> <app-inside-child></app-inside-child> <ng-content></ng-content>
7. inside child init
8. inside child after content init
进入 inside-child.html
<p>inside-child works!</p>
没有组件了, 所以开始 render view, 并且触发 AfterViewInit
9. inside child after view init
到目前为止的 console
回到 child.html
<p>child works!</p> <app-inside-child></app-inside-child> <ng-content></ng-content>
before render child component, 要先处理好 ng-content
这个 ng-content 内容是 transclude-to-child, 它已经 after content init 了.
进入 transclude-to-child.html
<p>transclude-to-child works!</p> <app-inside-transclude-to-child></app-inside-transclude-to-child>
10. inside transclude to child init
11. inside transclude to child after content init
进入 inside-transclude-to-child.html
<p>inside-transclude-to-child works!</p>
没组件了, render view
12. inside transclude to child after view init
回到 transclude-to-child.html
<p>transclude-to-child works!</p> <app-inside-transclude-to-child></app-inside-transclude-to-child>
没有组件了, render view
13. transclude to child after view init
回到 child.html
<p>child works!</p> <app-inside-child></app-inside-child> <ng-content></ng-content>
ng-content 也完成了, 现在 render view
14. child after view init
回到 app.html
<app-child> <app-transclude-to-child></app-transclude-to-child> </app-child>
15. app after view init
最后的 console
Changes Group Lifecycle Hooks
我建议大家先学 Change Detection 在回来看这个部分.
Changes group lifecycle hooks 和 change detection 比较有关联. 但我不想过度关注 change detection.
因为 Angular 要推出 Signal 了. change detection 会有重大改变. 某些相关的 lifecycle hooks 也会改. 所以这里大概讲一下就好了.
虽然 Changes Group Lifecycle Hooks 在 first time render 也会触发, 但很少会要用到,
所以这里我 focus 的是, 因为后续 event 而触发的 lifecycle.
DoCheck
1. 每当有异步事件发生, 比如 setTimeout, ajax, event dispatch, DoCheck 都会触发.
2. DoCheck 阶段是让我们告诉 Angular 组件是否要 detech change 的.
3. 这个阶段我们可以去修改 view model.
OnChanges
1. 每当 @Input 改变, 它就会触发, 包括 first time render (input from undefined to value) 也会.
2. 这个阶段我们任然可以去修改 view model
相关文章
- angular - 使用es6等一些功能
- Angular从零到一1.3 第一个小应用 Hello Angular
- Angular从零到一1.4 第一个组件
- angularjs link compile与controller的区别详解,了解angular生命周期
- angular ng-bind-html异常Attempting to use an unsafe value in a safe context处理
- Angular为什么选择TypeScript?
- "Uncaught object angular.js:36"诡异错误
- Angular injector注入器
- angular-input
- GIS教程之将 Plotly.js 与 Angular 一起使用
- 【angular】angular-ui-router学习