技巧问题我还没有在文档中找到任何答案。
当 AppRef.tick()
被调用时(主要是通过 NgZone 补丁),一个变化检测周期被触发。它从树顶部的根组件到底部经过:
- 具有默认策略的每个组件
- 每个由
markForCheck
标记的组件(及其祖先)
并跳过未标记的 OnPush 组件。
但是为什么当一个事件被一个组件触发时,它的所有祖先也会被检查?就像调用了 markForCheck
一样。
我期待与调用 AppRef.tick
时相同的行为。我不明白为什么要检查 OnPush parent 。在 this demo 上可以很好地看到这种行为.
最佳答案
也许你对OnPush的误解和我刚开始学习变化检测的时候一样:)。重点是:OnPush 策略不会改变任何关于触发 CD 周期的事件。这只是taken care of by zone.js by patching browser APIs . (除非手动触发 CD。)zone.js 不关心组件和 ChangeDetectionStrategies。并且 CD 总是从根目录开始为 @Chris Hamilton解释。
ChangeDetectionStrategy.Default 和 OnPush 的区别仅在于组件将在 CD 周期中实际被检查。
所以你原帖中的句子应该是: “已知 OnPush 策略仅在以下情况下标记要检查的组件”。
下面是我使用 Angular DevTools 的分析器观察到的示例.我在OnPush组件的ngOnInit中放了一个setTimeout(() => {}, 6000)
,它触发了一个CD循环(来源是“setTimeout”),但是并没有引起组件本身进行检查。
关于手动触发的detectChanges()、tick()和markForCheck()的区别:
ChangeDetectorReference.detectChanges()
通过尊重子组件的 CD 策略在此组件及其子组件上触发 CDApplicationRef.tick()
通过遵守 CD 策略为整个应用程序触发 CDChangeDetectorReference.markForCheck()
不会触发 CD,但会将所有 OnPush parents 标记为在当前或下一个 CD 周期中检查一次
(解释得很好 here )
=== 编辑:更新问题的答案===
如果浏览器事件监听器在 OnPush 组件中被触发,这将导致 OnPush 组件被标记为检查。此外,它还会触发从组件根部开始的更改检测。
如果我理解正确的话,你的问题是:为什么 OnPush 组件的所有父组件也必须标记为检查?
回答:如果一个OnPush组件没有被标记为check,那么不仅这个组件会被跳过,这个组件下面的整个子树也会被跳过。这意味着,如果事件处理程序被触发的组件有一个带有 OnPush 的父组件不会被检查,它本身也不会被检查。或者,反过来说,如果要检查一个组件,则还必须检查它的所有祖先。
关于angular - 尽管有 OnPush 策略,为什么 Angular 会在 DOM 事件的父组件上触发 ChangeDetection?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/71945490/