A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 郝永亮 于 2018-2-4 21:28 编辑

我不打算在这里罗列 API,在官方网站上面有更详细的描述和例子。


在这一节里面我们只讨论以下4件事:


什么是 UI 组件的生命周期?
Angular 组件的生命周期有什么特别的地方?
OnPush 策略的使用方式。
简要介绍脏检查的实现原理。
UI 组件的生命周期



无论使用什么样的前端框架,只要编写 UI 组件,生命周期都是必须要考虑的重要内容。请展开你的想象,如果让你来设计 UI 系统,组件有几个重要的阶段一定是绕不开的,比如:


初始化( init )阶段:
在这个阶段你需要把组件 new 出来,把一些属性设置上去,等等这些操作。


渲染( render )阶段:
在这个阶段需你要把组件的模板和数据结合起来,生成 HTML 标签结构,并且要整合到现有的 DOM 树里面去。


存活阶段:
既然带有 UI,那么在组件的存活期内就一定会和用户进行交互。一般来说,带有 UI 的系统都是通过事件机制进行用户交互的。也就是说,这个阶段将会处理大量的用户事件:鼠标点击、键盘按键、手指触摸。


销毁( destory )阶段:
最后,组件使用完了,需要把一些资源释放掉。最典型的操作:需要把组件上的所有事件全部清理干净,避免造成内存泄漏。
在组件生命的不同阶段,框架一般会暴露出一些“接口”,开发者可以利用这些接口来实现一些自己的业务逻辑。这种接口在有些框架里面叫做“事件”,在 Angular 里面叫做“钩子”,但其底层的本质都是一样的。


Angular 组件的生命周期钩子



Angular 一共暴露了8个“钩子”,构造函数不算。并没有组件或者指令会实现全部钩子。
绿色的4个钩子可能会被执行很多次,紫色的只会执行一次。
Content 和 View 相关的4个钩子只对组件有效,指令上不能使用。因为在新版本的 Angular 里面,指令不能带有 HTML 模板。指令没有自己的 UI,当然就没有 View 和 Content 相关的“钩子”了。
请不要在生命周期钩子里面实现复杂的业务逻辑,尤其是那4个会被反复执行的钩子,否则一定会造成界面卡顿。
真正在开发业务的过程中用到的可能只有三个:ngOnInit> ngOnChanges ngOnDestory。除非是你在写组件库会用到很多钩子
Angular新版本里面组件继承自指令,指令是不能带有视图的,组件带有视图
因为angular先处理自定义属性,所以先执行ngOnChanges,再执行ngOnInit
被@Input()修饰的变量发生改变时候才会触发ngOnChanges事件。如果该变量是对象并且只是修改了对象的某个熟悉而对象的地址没有发生变化则不会触发该事件
技巧:如果是@Input()修饰可变对象,如果要监听数据的改变应该用ngOnCheck,如果是不可变变量比如字符串,则可以是用ngOnChanges监听数据变化


变更检测的两种策略


Default:无论哪个组件发生了变化,从根组件开始全局遍历调用ngDoCheck();
OnPush:只有当组件的@Input属性发生变化的时候才调用笨组件的ngDoCheck();
添加策略的代码
import { ChangeDetectionStrategy} from '@angular/core';


@Component({
    selector: 'app-lift-cycle',
    templateUrl: './lift-cycle.component.html',
    styleUrls: ['./lift-cycle.component.scss'],
    encapsulation: ViewEncapsulation.None,
    changeDetection:ChangeDetectionStrategy.OnPush
})


OnPush 策略


在真实的业务系统中,组件会构成 Tree 型结构,就像这样:




当某个叶子组件上的数据模型发生变化之后,就像这样:




这时候,Angular 将会从根组件开始,遍历整颗组件树,把所有组件上的 ngDoCheck() 方法都调用一遍:





请注意,默认情况下,无论哪个叶子组件上发生了变化,都会把整个组件树遍历一遍。如果组件树非常庞大,嵌套非常深,很明显会有效率问题。在绝大部分时间里面,并不会出现每个组件都需要刷新的情况,根本没有必要每次都去全部遍历。所以 Angular 提供了一种叫做 OnPush 的策略,只要把某个组件上的检测策略设置为 OnPush,就可以忽略整个子树了,就像这样:





很明显,使用了 OnPush 策略之后,检查效率将会获得大幅度的提升,尤其在组件的数量非常多的情况下:





Angular 内置的两种变更检测策略:


Default:无论哪个组件发生了变化,从根组件开始全局遍历,调用每个组件上的 ngDoCheck() 钩子。
OnPush:只有当组件的 @Input 属性发生变化的时候才调用本组件的 ngDoCheck() 钩子。
有一些开发者建议 Angular 项目组把 OnPush 作为默认策略,但是目前还没有得到官方支持,或许在未来的某个版本里面会进行修改。


了解一点点原理


如果你不想看到扯原理的内容,可以跳过这一小段。





大家都知道,AngularJS 是第一个把“双向数据绑定”这种设计带到前端领域来的框架,“双向数据绑定”最典型的场景就是对表单的处理。


双向数据绑定的目标很明确:数据模型发生变化之后,界面可以自动刷新;用户修改了界面上的内容之后,数据模型也会发生自动修改。


很明显,这里需要一种同步机制,在 Angular 里面这种同步机制叫做“变更检测”。


在老版本 AgnularJS 里面,变更检测机制实现得不太完善,经常会出现检测不到变更的情况,所以才有了让大家很厌烦的 $apply() 调用。


在新版本的 Angular 里面不再存在这个问题了,因为新版本的 Angular 使用 Zone.js 这个库,它会把所有可能导致数据模型发生变更的情况全部拦截掉,从而在数据发生变化的时候去通知 Angular 进行刷新。


有一些朋友可能会觉得奇怪,Zone.js 怎么这么牛叉?它内部到底是怎么玩的呢?


实际上要做到这一点并不复杂,因为在浏览器环境下,有可能导致数据模型发生变化的情况只有3种典型的回调:


事件回调:鼠标、键盘、触摸
定时器回调:setTimeout 和 setInterval
Ajax 回调
Zone.js 覆盖了所有原生实现,当开发者在调用这些函数的时候,并不是调用的原生方法,而是调用的 Zone.js 自己的实现,所以 Zone.js 就可以做一些自己的处理了。

07 生命周期函数.png (534.08 KB, 下载次数: 20)

07 生命周期函数.png

0.008014892441651655.png (27.58 KB, 下载次数: 15)

0.008014892441651655.png

2 个回复

倒序浏览
回复 使用道具 举报
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马