【问题标题】:ngOnInit called in the middle of component lifetimengOnInit 在组件生命周期中间调用
【发布时间】:2018-03-11 03:25:49
【问题描述】:

text.component(选择器 app-text)在应用程序生命周期的中间(不仅仅是我创建它时)初始化时遇到了一些问题。

这是 app.component.html:

  <div class="container-fluid" *ngFor="let text of texts;let i=index">
    <app-text (textInfoEmitter)="dataFromChild($event)" [elementId]=i  [ngStyle]="{'transform': getRotation(i), 'font-size.px':getFontSize(i)}" ></app-text>
  </div>

我使用textInfoEmitter 函数从app-text 发出数据,并使用dataFromChild(e) 更新app.component.ts 中的模型。

我注意到每次textInfoEmitter 发出,app-text 都会重新初始化。我可以确认,因为 ngOnInitconstructor 函数被调用。

这是 app.component.ts 文件:

export class AppComponent implements OnInit {
  texts: [TextModel];

  ngOnInit() {
    this.texts = [
      {
        rotation: 30,
        fontSize: 16,
        offset: { left: 120, top: 200 },
        scale: 1.4
      }
    ]
  }

  dataFromChild(e) {
    this.texts[e.elementID] = {
      rotation: e.rotation,
      fontSize: e.fontSize,
      offset:e.offset,
      scale: 1
    }

  }
  getRotation(i: number) {
    return "rotate(" + this.texts[i].rotation + "deg)";
  }
  getFontSize(i: number) {
    return this.texts[i].fontSize;
  }
}

text.component.ts 很复杂,我还没有找到在线复制复杂 Angular 项目的方法。这是我调用的 emit 辅助函数:

  emitData(e){
    if ($(e).hasClass("h")){
      this.parentId = $(e).attr("id");
    }else{
      this.parentId = $(e).parent().attr("id");
    }

    this.textInfoEmitter.emit(
      {
        elementID: this.parentId,
        rotation: this.delta.circleX,
        fontSize: this.delta.fontSize,
        offset: {
          left: this.drag.x,
          top: this.drag.y
        }
      }
    );
  }

deltadragtext.component.ts 中的模型。

我的问题是,在什么情况下组件会在生命周期内重新初始化?如何防止这种情况?

问题的副本。我基本上也在做同样的事情,使用 ngFor 指令并使用 EventEmitter 更新模型。这一次,模型更新时不会触发 ngOnInit。

app.component.ts

import { Component } from '@angular/core';
declare var $;
@Component({
  selector: 'app-root',
  template: `
  <div class="container-fluid" *ngFor="let text of texts; let i = index">
<app-text id="i" (dataEmitter)="setData($event)" [ngStyle]="{'transform': getRotation()}"></app-text>
</div>
  `,
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  texts = [
    {rotate:10}
  ];

  ngOnInit(){
  }
  getRotation(){
    return "rotate("+this.texts[0].rotate+"deg)";
  }
  setData(e){
      this.texts[0].rotate = e;
  } 
}

text.component.ts

import { Component, OnInit, Output, EventEmitter } from '@angular/core';
declare var $;
@Component({
  selector: 'app-text',
  template:`<div tabindex="-1" (mousedown)="mousedown($event)" (focusout)="focusout($event)">Text</div>` ,
  styleUrls: ['./text.component.css']
})
export class TextComponent implements OnInit {

@Output() dataEmitter = new EventEmitter();
  constructor() { }

  ngOnInit() {
    console.log("ng on Init");
  }
  mousedown(e){
    $(e.target).focus();
    $(e.target).addClass("selected");
    this.dataEmitter.emit(50);
  }
  focusout(e){
    console.log("f out");
    $(e.target).removeClass("selected");
  }
}

【问题讨论】:

    标签: angular ngoninit


    【解决方案1】:

    感谢@dee zg,问题解决了。

    当模型改变时,Angular 确实会重新初始化 *ngFor 指令的全部内容。在底层,它会尝试确定是否需要销毁和创建 dom 元素。

    如果你修改整个模型对象,angular会创建新的dom元素,但如果你只修改模型对象的属性,它不会。

    例如:

    this.texts[0] = {rotation:0, fontSize:23} 将导致 ngFor 的内容被销毁并重新创建。

    但是如果你使用这个:

    this.texts[0].rotation = 0;
    this.texts[0].fontSize = 23;
    

    不会。

    【讨论】:

    • 当然因为这不会改变对对象的引用。
    【解决方案2】:

    您正在更改 this.texts 属性,即 *ngFor 绑定到的属性,而该属性又是 app-text 组件的父级。

    这意味着:

    1. 你变了this.texts
    2. *ngFor 为之前的 this.texts 值创建的 DOM 元素被删除(连同所有 app-text 子组件)
    3. this.texts 的新迭代发生在每个 app-text 的新实例中

    【讨论】:

    • 我添加了另一个代码,这是一个问题的复制品。我正在使用 ngFor 并发出数据,就在之前。但在这种情况下,模型更新时不会触发 ngOnInit。
    猜你喜欢
    • 2017-01-06
    • 2018-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-05
    • 1970-01-01
    相关资源
    最近更新 更多