首页 文章

Angular OnPush Component,当触发事件在视角度力markForCheck自动?

提问于
浏览
1

阅读Zone.JS并更改检测过程,在源代码中,Zone.JS通过传播对所有组件的检查来通知Angular它从上到下运行第一个组件的变化,但在我的测试中,我有不同的行为 .

检查我的样本:

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

该示例具有以下体系结构:

<app-component>
    <child-component>
        <grand-child-component>

它们彼此嵌套,没有@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

很酷,但是,现在让我们想象一下,如果盛大的孩子会引发一个事件?

改变大孩子的观点

<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或detectchanges,但上面的代码看起来像我调用了markforcheck .

我在grand-child组件中使用ts中的observable调用了settimeout,interval和events,并且没有调用更改(检查grand-component ts),只在视图中(单击)调用check ...

您可以使用以下命令进行验证:在子项或app组件中,您可以添加增加值的setInterval并且您可以在视图中检查,只有当孙子触发您的祖先的(点击)值时才能实现更新了!

我意识到:settimeout,interval或者在组件的ts内具有observable的事件以及当组件是OnPush时事件在app组件中启动但它们没有被“强制传播”,因为@Input没有变化,但是当我们在视图中添加事件,比如(点击)某些通过模拟markForCheck强制它们的方式,实际发生了什么?

当我们在视图中添加一个事件时,引擎盖下的Angular会强制执行markForCheck();到组件?因为这似乎发生了什么 .

1 回答

  • 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);
    }
    

    也可以看看

相关问题