代码之家  ›  专栏  ›  技术社区  ›  Mario Petrovic Emmanuel Onah

当用户将鼠标悬停在Openlayers地图上时,角度会重新调整

  •  0
  • Mario Petrovic Emmanuel Onah  · 技术社区  · 4 年前

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

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

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

    我想用插件或codesanbox创建可在线运行的窗口,但当我让这个示例窗口冻结时,因为重新渲染中有无休止的循环,这使得它们无法使用,当我在本地运行这个项目时,这种情况并没有真正发生,它只会在悬停时发生

    谢谢。

    0 回复  |  直到 4 年前
        1
  •  3
  •   Daniel W Strimpel Michael Dorgan    4 年前

    克隆您的仓库以查看内容后,有两件事。

    首先,用例非常简单,因此您不会看到使用推送更改检测策略的所有好处,因为它不会导致非根组件具有更改检测周期(如果所有组件都使用推送策略)。

    其次,由于底层映射库(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 .