【发布时间】:2020-08-26 00:00:19
【问题描述】:
简单地说,我在组件的模板中有一个元素。这个元素有一个ngIf 条件和一个(click) 处理程序。它不是从一开始就呈现的,因为 ngIf 条件的计算结果为 false。
现在到了有趣的部分:在角度区域外部运行的代码将该条件更改为true,并且在手动对更改检测器引用执行detectChanges 后,该元素被渲染并且点击处理程序 ofc 变为活动状态。
目前看来一切正常,但问题是当用户点击后运行(click) 回调时,不会触发组件的更改检测。
这里是复制https://stackblitz.com/edit/angular-kea4wi
在那里重现它的步骤:
- 点击米色区域
- 按钮出现,也点击一下
- 没有任何反应,尽管消息应该出现在下方
说明:
-
米色区域有一个通过 addEventListener 注册的点击事件处理程序,并且这个事件监听器的回调运行在角区域之外。在其中,组件的
showButton属性从false设置为true,我通过调用detectChanges()手动触发更改检测,否则showButton属性中的更改将不会被注册。代码如下所示:this.zone.runOutsideAngular(() => { const el = this.eventTarget.nativeElement as HTMLElement; el.addEventListener('click', e => { this.showButton = true; this.cd.detectChanges(); }) }) -
出现现在按钮,这要归功于
*ngIf="showButton"最初没有呈现,并且它有一个在模板中声明的点击事件处理程序。此处理程序再次更改组件的属性,这次将showMessage更改为true。<button *ngIf="showButton" (click)="onButtonClick()">Click me!</button> onButtonClick() { this.showMessage = true; } 当我单击它时,处理程序显然会运行并将组件的
showMessage更改为true,但它不会触发更改检测,并且不会出现下面的消息。 要使示例正常运行,只需从一开始就将 showButton 设置为 true,然后上面的场景就可以正常运行。
问题是:这怎么可能?由于我在模板中声明了(click) 事件处理程序,它不应该总是在调用时触发更改检测吗?
【问题讨论】:
-
带有 stackblitz 演示的重现步骤会很棒!
-
我的猜测是单击时会触发更改检测,但是由于它从根组件开始并且根组件具有
OnPush,因此它会停在那里并且不会检查组件树下的其他组件。 -
@alt255 点击事件应该绕过
OnPush层次结构,并在适当的位置触发更改检测 - 在它冒泡的组件中(DOM 方式)。否则这将是一个相当普遍的问题和 Angular 的设计缺陷。 -
see this for details 这验证了我上面的观点
-
@alt255 如果是这种情况,为什么在描述的场景之外单击箭头会起作用呢?就像我用画廊刷新页面并多次单击下一步和上一个箭头一样。它会更新计数器。
标签: javascript angular angular-changedetection