Angular2 - 钩子

这节我们主要学习。Angular的钩子。他是伴随着Angular的生命周期存在的。下面我们就来介绍Angular中有那些钩子

钩子

用途及时机

ngOnChanges()

当 Angular(重新)设置数据绑定输入属性时响应。 该方法接受当前和上一属性值的 SimpleChanges 对象

当被绑定的输入属性的值发生变化时调用,首次调用一定会发生在 ngOnInit() 之前。

ngOnInit()

在 Angular 第一次显示数据绑定和设置指令/组件的输入属性之后,初始化指令/组件。

在第一轮 ngOnChanges() 完成之后调用,只调用一次。

ngDoCheck()

检测,并在发生 Angular 无法或不愿意自己检测的变化时作出反应。

在每个 Angular 变更检测周期中调用,ngOnChanges() 和 ngOnInit() 之后。

ngAfterContentInit()

当把内容投影进组件之后调用。

第一次 ngDoCheck() 之后调用,只调用一次。

ngAfterContentChecked()

每次完成被投影组件内容的变更检测之后调用。

ngAfterContentInit() 和每次 ngDoCheck() 之后调用

ngAfterViewInit()

初始化完组件视图及其子视图之后调用。

第一次 ngAfterContentChecked() 之后调用,只调用一次。

ngAfterViewChecked()

每次做完组件视图和子视图的变更检测之后调用。

ngAfterViewInit() 和每次 ngAfterContentChecked() 之后调用。

ngOnDestroy()

当 Angular 每次销毁指令/组件之前调用并清扫。 在这儿反订阅可观察对象和分离事件处理器,以防内存泄漏。

在 Angular 销毁指令/组件之前调用。

 

从上面的表格可以看出ngOnChanges() 发生在所以变化之前。

  • ngOnChange,当component的值发生改变的时候我们可以对发生改变的值做一些操作,下面例子中在SimpleChanges发生改变的时候我们可以获取改变之前的值和改变之后的值。

值得注意的是。当我们传入的类,并且改变类中的属性值。Angular并没有做出改变。应为Angular认为类作为引用类型。他的引用地址并没有发生改变。

ngOnChanges(changes: SimpleChanges) {
  for (let propName in changes) {
    let chng = changes[propName];
    let cur  = JSON.stringify(chng.currentValue);
    let prev = JSON.stringify(chng.previousValue);
    this.changeLog.push(`${propName}: currentValue = ${cur}, previousValue = ${prev}`);
  }
}
  • ngOnInit,我们可以使用ngOnInit在构造函数之后执行初始化逻辑,和对组件进行准备,在一般情况下。Angular不建议在构造函数中获取数据。所以在ngOnInit就成了初始化的最佳选择。
  • ngDoCheck,可以检测一些相关的值。并捕获当前值和以前的值进行比较。这里就可以检测到类中的改变。但是我们输出log可以发现。doCheck调用太过频繁,每一次更改都会有接近20次的调动。即使鼠标滑过button也会有doCheck的方法调用。

     只有相对较少的调用才是由于对相关数据的修改而触发的。 显然,我们的实现必须非常轻量级,否则将损害用户体验.

  • AfterContent,AfterContentInit和AfterContentChecked 钩子都是成对出现的。Angular会在外来内容被投影到主键之后调用。
    • 内容投影 : 指从外部引入HTML内容。查到到宿主模板的一直途径

@Component({
  selector: 'app-heroes',
  templateUrl: '<after-content>
           <app-child></app-child>
           </after-content>',//
  styleUrls: ['./heroes.component.sass']
})

  • AfterView ,AfterViewInit 和 AfterViewChecked 钩子也是成对出现的。Angular会在每次创建子视图后调用他们。即当你的component的模板中调用了其他的component视图。
@Component({
  selector: 'app-heroes',
  templateUrl: '<div>-- child view begins --</div> 
                <app-child-view></app-child-view> 
                <div>-- child view ends --</div>',//
  styleUrls: ['./heroes.component.sass']
})

AfterContent 钩子和 AfterView 相似。关键的不同点是子组件的类型不同。

  • AfterView 钩子所关心的是 ViewChildren,这些子组件的元素标签会出现在该组件的模板里面。

  • AfterContent 钩子所关心的是 ContentChildren,这些子组件被 Angular 投影进该组件中。

AfterContent 钩子基于子级内容中值的变化而采取相应的行动,它只能通过带有@ContentChild装饰器的属性来查询到“子级内容”。

export class AfterContentComponent implements AfterContentChecked, AfterContentInit {
  private prevHero = '';
  comment = '';

  // Query for a CONTENT child of type `ChildComponent`
  @ContentChild(ChildComponent) contentChild: ChildComponent;

  ngAfterContentInit() {
    // contentChild is set after the content has been initialized
    this.logIt('AfterContentInit');
    this.doSomething();
  }

  ngAfterContentChecked() {
    // contentChild is updated after the content has been checked
    if (this.prevHero === this.contentChild.hero) {
      this.logIt('AfterContentChecked (no change)');
    } else {
      this.prevHero = this.contentChild.hero;
      this.logIt('AfterContentChecked');
      this.doSomething();
    }
  }
  // ...
}

使用 AfterContent 时,无需担心单向数据流规则

该组件的 doSomething() 方法立即更新了组件被绑定的 comment 属性。 它不用等下一回合。

Angular 在每次调用 AfterView 钩子之前也会同时调用 AfterContent。 Angular 在完成当前组件的视图合成之前,就已经完成了被投影内容的合成。 所以你仍然有机会去修改那个视图

 

我们新建一个新的Component,来观察一个全新的Component调用了哪些钩子。

  ngOnChanges() {
    console.log('ngOnChanges is invoded.');
  }

  ngOnInit() {
    console.log('ngOnInit is invoked.');
  }

  ngDoCheck() {
    console.log('ngDoCheck is invoked');
  }

  ngAfterContentInit() {
    console.log('ngAfterContentInit is invoked');
  }

  ngAfterContentChecked() {
    console.log('ngAfterContentChecked is invoked');
  }

  ngAfterViewInit() {
    console.log('ngAfterViewInit is invoked');
  }

  ngAfterViewChecked() {
    console.log('ngAfterViewChecked is invoked');
  }

  ngOnDestroy() {
    console.log('ngOnDestroy is invoked');
  }

我们可以看到ngOnInit 调用,ngDoCheck(+2),ngAfterContentInit和ngAfterContentChecked (+1),ngAfterViewInit和ngAfterViewChecked(+1),

但是我们发现ngAfterContentChecked,和ngAfterViewChecked被单独各调用了一次。这是很意外的事情。

我们new一个Hero对象。并把name属性绑定到input中。

我们发现当修改那么属性的值。Angular都会调用, doCheck,afterContent,afterView,

这就可以理解当Component加载之初的最后三个钩子的调用,是作为对Component的check。

接着我们给Component添加一个输入参数@Input,当我们在Parent Component中修改Input的值的时候。onChange钩子被调用。

  @Input() size: number;

  ngOnChanges(size) {
    console.log('ngOnChanges is invoded.');
  }

我们可以看到onChange子和之前的三个check的钩子一起被调用。

 

posted @ 2018-12-21 16:15  Allen●J  阅读(182)  评论(0编辑  收藏  举报