AngularOnPush组件,DOM事件是否强制Angular自动调用markForCheck()?
Angular OnPush Component, does DOM event force Angular to call markForCheck() automatically?
我正在阅读有关 Zone.JS 和 Angular 更改检测过程的信息,在代码源中,Zone.JS 通知 Angular 有关更改和 运行通过将检查传播到所有组件,从上到下在第一个组件中进行验证,但在我的测试中,我有奇怪的行为。
检查我的样本:
http://plnkr.co/edit/QPHBQ7cYg9JFZr2oVnGZ?p=preview
示例具有以下架构:
<app-component>
<child-component>
<grand-child-component>
它们相互嵌套,其中none个具有@Input属性,并且都是OnPush,它们在视图中显示一个简单的值,如:
查看:
{{getComponentValue}}
打字稿
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
很酷,但是,现在让我们创建一个场景,如果孙子触发了 DOM 事件?
改变孙子的看法
<button (click)="undefined"> {{getComponentValue}} </button>
<!-- (click)="undefined" trigger an event -->
然后我们有日志:
check component app
check component child
check component grand child
我原以为当我点击孙子按钮时,事件会在应用程序组件中启动,
但由于它们都是 OnPush,事件不会捕获孙子组件,因为没有更改 @Input 属性,我将不得不手动调用 markforcheck 或 detectchanges,但上面的代码看起来像我调用了markforcheck.
我在孙子组件中调用了 settimeout、interval 和带有可观察对象的事件,其中 none 调用了更改(检查 grand-component ts),仅查看事件(单击)检查被调用。 ..
正在进行验证,您可以进行测试,例如:在子组件或应用程序组件中,您可以添加增加值的 setInterval
而且你可以查看视图,发现只有当孙子触发时,你祖先的(点击)值才会更新!
因此当 DOM 事件被触发时,他们是通过模拟 markForCheck() 来强制执行的吗?
是的,这是设计使然:一个绑定事件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);
}
另见
我正在阅读有关 Zone.JS 和 Angular 更改检测过程的信息,在代码源中,Zone.JS 通知 Angular 有关更改和 运行通过将检查传播到所有组件,从上到下在第一个组件中进行验证,但在我的测试中,我有奇怪的行为。
检查我的样本:
http://plnkr.co/edit/QPHBQ7cYg9JFZr2oVnGZ?p=preview
示例具有以下架构:
<app-component>
<child-component>
<grand-child-component>
它们相互嵌套,其中none个具有@Input属性,并且都是OnPush,它们在视图中显示一个简单的值,如:
查看:
{{getComponentValue}}
打字稿
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
很酷,但是,现在让我们创建一个场景,如果孙子触发了 DOM 事件?
改变孙子的看法
<button (click)="undefined"> {{getComponentValue}} </button>
<!-- (click)="undefined" trigger an event -->
然后我们有日志:
check component app
check component child
check component grand child
我原以为当我点击孙子按钮时,事件会在应用程序组件中启动, 但由于它们都是 OnPush,事件不会捕获孙子组件,因为没有更改 @Input 属性,我将不得不手动调用 markforcheck 或 detectchanges,但上面的代码看起来像我调用了markforcheck.
我在孙子组件中调用了 settimeout、interval 和带有可观察对象的事件,其中 none 调用了更改(检查 grand-component ts),仅查看事件(单击)检查被调用。 ..
正在进行验证,您可以进行测试,例如:在子组件或应用程序组件中,您可以添加增加值的 setInterval 而且你可以查看视图,发现只有当孙子触发时,你祖先的(点击)值才会更新!
因此当 DOM 事件被触发时,他们是通过模拟 markForCheck() 来强制执行的吗?
是的,这是设计使然:一个绑定事件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);
}
另见