阅读Zone.JS并更改检测过程,在源代码中,Zone.JS通过传播对所有组件的检查来通知Angular有关更改它从上到下运行第一个组件,但在我的测试中,我有一个不同的行为。
检查我的样本:
http://plnkr.co/edit/QPHBQ7cYg9JFZr2oVnGZ?p=preview
该示例具有以下架构:
<app-component>
<child-component>
<grand-child-component>
它们彼此嵌套,没有@Input属性,并且它们都是OnPush,它们在视图中显示一个简单的值,如:
视图:
{{getComponentValue}}
typescript
value = "app component";
get getComponentValue() { // <-- ES6 get to log when Angular check
console.log('change detection checking here in component app-component')
return this.value;
}
您可以在示例中查看此代码。
当应用程序启动时,我们可以看到日志:
check component app
check component child
check component grand child
很酷,但是,现在让我们想象一下,如果爷爷会触发一个事件?
更改大孩子的视野
<button (click)="undefined"> {{getComponentValue}} </button>
<!-- (click)="undefined" cria um inscrito no evento. -->
我们有日志:
check component app
check component child
check component grand child
我期望:当我点击了子孙按钮时,该事件将从app-component开始, 但由于所有这些都是OnPush,因此事件不会因为没有更改@Input而进入盛大孩子,我必须手动调用markforcheck或者检测更改,但上面的代码看起来像是我调用了markforcheck。 / p>
我在grand-child组件的ts中调用了settimeout,interval和event with observables,并且没有调用更改(检查grand-component ts),只在视图中(单击)调用check ...
您可以使用以下命令进行验证:在子组件或app组件中,您可以添加增加值的setInterval 你可以查看视图,意识到只有当孙子触发你的祖先的(点击)值时才会更新!
我意识到:settimeout,interval或在组件的ts内具有可观察对象的事件以及组件为OnPush时 某些事件在应用程序组件中启动,但它们没有“强行传播”,因为@Input没有变化,但是当我们在视图中添加事件时,就像某些事件的(点击)一样 通过模拟markForCheck强制它们的方式,实际发生了什么?
当我们在视图中添加一个事件时,引擎盖下的Angular会强制执行markForCheck();到组件? 因为那似乎发生了。
答案 0 :(得分:2)
是的,这是设计的:内部绑定事件triggers markForCheck
export function dispatchEvent(
view: ViewData, nodeIndex: number, eventName: string, event: any): boolean {
const nodeDef = view.def.nodes[nodeIndex];
const startView =
nodeDef.flags & NodeFlags.ComponentView ? asElementData(view, nodeIndex).componentView : view;
markParentViewsForCheck(startView); // <== this line
return Services.handleEvent(view, nodeIndex, eventName, event);
}
另见