【问题标题】:Angular rerenders when user hovers over Openlayers map当用户将鼠标悬停在 Openlayers 地图上时,角度会重新渲染
【发布时间】:2020-02-07 22:12:47
【问题描述】:

我在我的项目中使用 Openlayers 6 和 Angular 8。 到目前为止,我注意到每当我将鼠标悬停在 Openlayers 地图上时,地图所在的 Angular 组件都会重新渲染。

我的问题是如何让父组件在悬停时停止重新渲染。因为它会减慢应用程序的速度。我的项目中有一个更大的组件,因此重新渲染所有内容,这会使应用程序本身变慢。

为此,我创建了一个 repo 来证明这一点:https://github.com/petrovichm/angular-openlayers-hover-problem。 在此示例中,我在 html 中添加了一个方法,该方法将在运行时记录下来,从而概述了角度重新渲染组件的次数。

我想使用 plunker 或 codesanbox 创建在线可运行文件,但是当我制作此示例窗口时,由于重新渲染中存在无限循环,导致它们无法使用,所以当我在本地运行此项目时,它并没有真正发生这种情况,它只发生在悬停时

谢谢。

【问题讨论】:

  • 您是否尝试过使用 on push 更改检测策略来防止这种情况? @Component({ ..., changeDetection: ChangeDetectionStrategy.OnPush })这应该可以防止您正在谈论的问题。
  • 是的,它仍然会重新渲染。

标签: angular openlayers angular-components openlayers-6 angular-renderer


【解决方案1】:

克隆你的 repo 来查看之后,有两件事。

首先,用例非常简单,因此您不会看到使用推送更改检测策略的所有好处,该策略可以缓解大部分问题,因为它不会导致非根组件进行更改检测循环(如果所有组件都使用 on push 策略)。

其次,由于底层地图库 (OpenLayers) 将事件附加到 DOM 节点本身,这将导致 Angular 的更改检测由于 zone.js 拦截事件处理而触发。为了防止这种情况,您必须在 Angular 区域之外设置地图:

import { ..., NgZone } from '@angular/core';

...
export class AppComponent implements OnInit {
  ...

  construtor(private zone: NgZone) {
  }

  ...

  ngOnInit() {
    this.zone.runOutsideAngular(() => {
      this.map = new Map({ ... });
    });
  }
}

在 Angular 区域之外运行东西时必须小心,但在这里这样做可以防止出现问题。您必须将地图事件处理中的任何逻辑包装回 Angular 区域中,以便 Angular 知道更新。

export class AppComponent implements OnInit {
  currentValue = 0;

  ...

  ngOnInit() {
    this.zone.runOutsideAngular(() => {
      this.map = new Map({ ... });
    });

    this.map.on('click', (e) => {
      this.currentValue++; // Angular will not pick up this change because it will run outside of the Angular zone
    });

    this.map.on('click', (e) => {
      this.zone.run(() => {
        this.currentValue++; // Angular will pick up this change because it will run inside the Angular zone
      });
    });
  }
}

这是一篇很好的博文,我认为可以进一步帮助理解这一点:https://netbasal.com/optimizing-angular-change-detection-triggered-by-dom-events-d2a3b2e11d87

【讨论】:

  • 嘿伙计,谢谢你的提示。下周我会尝试一下,然后给你反馈。我不知道你可以像那样从区域中分离出来。我用 detecChanges.detach() 服务方法做到了。但它也不起作用。再次感谢
  • 这个解决方案确实有效。感谢您的回答。它会做一个更大的样板,但是嘿,它肯定会加快应用程序的速度。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-08-22
  • 2018-05-07
  • 2015-06-04
  • 2012-12-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-21
相关资源
最近更新 更多