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

标签 angular angular2-changedetection

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

检查我的样本:

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

示例具有以下架构:

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

它们相互嵌套,它们都没有@Input 属性,它们都是 OnPush,它们在 View 中显示一个简单的值,如:

查看:

{{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

很酷,但是,现在让我们创建一个场景,如果孙子触发 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,但上面的代码看起来像我调用了标记检查。

我在孙子组件中使用可观察对象调用了 settimeout、interval 和 events,但它们都没有调用更改(检查 grand-component ts),仅查看事件(单击)检查被调用...

验证正在进行,您可以测试例如:在子组件或应用程序组件中,您可以添加增加值的 setInterval 你可以查看 View ,意识到只有当孙子触发时,你祖先的(点击)值才会更新!

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

最佳答案

是的,这是设计使然:绑定(bind)事件 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);
}

另见

关于Angular OnPush 组件,DOM 事件是否强制 Angular 自动调用 markForCheck()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45287556/

相关文章:

angular - 'stream' 的所有声明必须具有相同的修饰符 api-ai-javascript - Dialogflow

javascript - 从接口(interface)导出枚举

javascript - 当前在 Angular 应用程序中没有初始化 firebase.app.App 实例

angular - 谁拥有 Angular Dart 中的 TemplateRef 刷新周期?

angular - 当属性在 angular 4 中没有改变时如何强制更新模板

angular - 当 Angular 可以检测到最新值时,为什么要在服务中使用 Subject 或 BehaviorSubject?

Angular2 模板表达式在变更检测时为每个组件调用两次

javascript - 使用 IterableDiffer 在 Angular 8 中获取数组大小更改

angular - 即使列表引用发生变化,如何重用 ngFor 的元素?

Angular2 Routing - 在路由更改时保持组件状态