Angular OnPush 组件,DOM 事件是否强制 Angular 自动调用 markForCheck()?

Gus*_*sta 2 angular2-changedetection angular

我正在阅读有关 Zone.JS 和 Angular 更改检测过程的信息,在代码源中,Zone.JS 通过将检查传播到所有组件来通知 Angular 有关更改并在第一个组件中从上到下运行验证,但在我的测试,我有奇怪的行为。

检查我的样本:

http://plnkr.co/edit/QPHBQ7cYg9JFZr2oVnGZ?p=preview

该示例具有以下架构:

<app-component>
    <child-component>
        <grand-child-component>
Run Code Online (Sandbox Code Playgroud)

它们相互嵌套,都没有 @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;
}
Run Code Online (Sandbox Code Playgroud)

您可以在示例中检查此代码。

当应用程序启动时,我们可以看到日志:

check component app
check component child
check component grand child
Run Code Online (Sandbox Code Playgroud)

很酷,但是,现在让我们创建一个场景,如果孙子触发 DOM 事件?

改变孙子的观点

<button (click)="undefined"> {{getComponentValue}} </button>  
<!-- (click)="undefined" trigger an event -->
Run Code Online (Sandbox Code Playgroud)

然后我们有日志:

check component app
check component child
check component grand child
Run Code Online (Sandbox Code Playgroud)

我期待当我点击孙子按钮时,事件将在应用程序组件中启动,但由于它们都是 OnPush,事件不会捕获孙子组件,因为没有 @Input 属性' t 改变了,我必须手动调用markforcheck 或detectchanges,但上面的代码看起来像我调用了markforcheck。

我在孙子组件中调用了 settimeout、interval 和带有 observables 的事件,但它们都没有调用更改(检查大组件 ts),仅查看事件(单击)该检查被称为...

验证正在发生,您可以测试例如:在子组件或应用程序组件中您可以添加增加值的 setInterval 并且您可以检查视图,意识到只有当孙子触发您祖先的(点击)值时已更新!

因此,它们是通过在触发 DOM 事件时模拟 markForCheck() 来强制执行的,实际上是否正在发生?

yur*_*zui 5

是的,这是设计使然:绑定事件在内部触发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);
}
Run Code Online (Sandbox Code Playgroud)

也可以看看