我读过 Angular 2 更改检测...在单次通过后变得稳定
Angular 2 并不“稳定”。对于 Angular 2 应用程序,我们负责编写应用程序,使其在单次通过后始终保持稳定。
默认情况下(例如,您没有OnPush
在任何组件上使用更改检测策略,也没有detach()任何组件),更改检测的工作方式如下:
- 一个 Zone.js 猴子补丁异步事件触发——例如,一个
(click)
事件、一个 XHR 响应、一个setTimeout()
计时器。与该事件关联的回调运行,它可以更改我们应用程序中的任何视图或应用程序数据。然后,由于猴子补丁,Angular 变化检测运行。换句话说,默认情况下(例如,您没有手动触发更改检测),只有猴子补丁异步事件触发更改检测。
- 从根组件开始,向下遍历组件树(深度优先遍历),检查每个数据绑定是否有更改。如果发现更改,则更改被“传播”。根据模板绑定类型,传播可能
- 将更改后的值传播到 DOM。例如,当
{{}}
使用绑定时,新值会传播到textContent
适当的 DOM 元素的属性。
- 将更改的值传播到子组件。例如,当使用输入属性绑定 (
[childInputProperty]="parentProperty"
) 时,新值会传播到子输入属性。
- 如果您处于开发模式,则会再次对所有组件进行脏检查,但不会发生传播。第二次脏检查帮助我们发现代码的问题,例如,如果我们违反了幂等规则,这是说我们的一个绑定(它的模板表达式)有副作用的奇特方式。换句话说,额外的开发模式检查让我们知道我们的代码在单次通过后是否不稳定。
Angular 2 中不允许出现副作用。关于您的问题,因此子组件不得因输入属性传播而修改父属性。因此,您可以说 Angular 2 通过不允许它“解决”了您所询问的情况。
这并不像听起来那么糟糕。我知道输入属性传播可以更改父属性的唯一方法是子组件是否为输入属性实现了一个 setter 方法,该方法修改了父组件在其模板中显示的另一个属性。(这是一个做这个的老笨蛋——见@Input set backdoor()
方法。)通常你不会这样做。如果您确实需要这样做,那么 Günter 的评论就是:在 a 内进行更改setTimeout()
,因此它将成为下一个更改检测周期的一部分。
我想再次强调:事件处理程序在更改检测之前运行,因此它们可以自由更改我们应用程序中的任何数据——本地/组件视图数据、应用程序数据等等。因此,在事件处理程序中,子组件可以自由更改父数据。例如,假设父母和孩子都有对同一个数组的引用。当事件处理程序运行时,父和/或子组件可以修改该数组。
因此,如果您在事件处理程序中进行更改,没问题。只有当你的二传手做了一些奇怪的事情时才会有问题。