ngOnInit 在组件生命周期中间调用
Posted
技术标签:
【中文标题】ngOnInit 在组件生命周期中间调用【英文标题】:ngOnInit called in the middle of component lifetime 【发布时间】: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
都会重新初始化。我可以确认,因为 ngOnInit
和 constructor
函数被调用。
这是 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
);
delta
和 drag
是 text.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");
【问题讨论】:
【参考方案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
组件的父级。
这意味着:
-
你变了
this.texts
*ngFor
为之前的 this.texts
值创建的 DOM 元素被删除(连同所有 app-text
子组件)
this.texts
的新迭代发生在每个 app-text
的新实例中
【讨论】:
我添加了另一个代码,这是一个问题的复制品。我正在使用 ngFor 并发出数据,就在之前。但在这种情况下,模型更新时不会触发 ngOnInit。以上是关于ngOnInit 在组件生命周期中间调用的主要内容,如果未能解决你的问题,请参考以下文章