Angular 6 - 如果导入 BrowserAnimationsModule (Openlayers) 会出现渲染问题

Angular 6 - Rendering problems if BrowserAnimationsModule imported (Openlayers)

我基本上有一个呈现小地图的应用程序。此页面上还有一个 "toggle" 按钮,它在父组件中隐藏带有 *ngIf 的小地图,并以大地图显示。 如果我现在在 app.module.ts 中导入 BrowserAnimationsModule,那么如果我单击切换按钮(仅当我在 map-base.component.ts 的 ngOnInit 中创建地图之前设置了 1 毫秒的超时),则不会渲染大地图。

抱歉..有点难以解释,这是代码:

App.module.ts

...
@NgModule({
  declarations: [
    AppComponent,
    MapSmallComponent,
    MapLargeComponent,
    MapBaseComponent
  ],
  imports: [
    BrowserModule,
    FormsModule,
    BrowserAnimationsModule, // comment this line, to make the app work
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

app.component.ts

@Component({
  selector: 'app-root',
  template: `
  <app-map-small *ngIf="small"></app-map-small>
  <app-map-large *ngIf="!small"></app-map-large>
  <button (click)="small = !small">Toggle</button>`,
  styleUrls: ['./app.component.scss']
})
export class AppComponent {
  small = true;
}

地图-base.component.ts

@Component({
  selector: 'app-map-base',
  template: `<div id="map" class="map"></div>`,
  styleUrls: ['./map-base.component.scss']
})
export class MapBaseComponent implements OnInit {
  map: OlMap;
  constructor() { }

  ngOnInit() {
    this.map = new OlMap({
      target: 'map',
      layers: [new OlTileLayer({ source: new OlOSM() })],
      view: new OlView({ zoom: 13, center: fromLonLat([13.376935, 52.516181]) }),
      controls: []
    });
  }
}

地图-small.component.ts

@Component({
  selector: 'app-map-small',
  template: `
    <p>other stuff</p>
    <div style="max-width:500px">
      <app-map-base></app-map-base>
    </div>
    <p>other stuff2</p>
  `,
  styleUrls: ['./map-small.component.scss']
})
export class MapSmallComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

地图-large.component.ts

@Component({
  selector: 'app-map-large',
  template: `
  <p>Some other stuff</p>
  <app-map-base></app-map-base>`,
  styleUrls: ['./map-large.component.scss']
})
export class MapLargeComponent implements OnInit {

  constructor() { }

  ngOnInit() {
  }
}

依赖项

"dependencies": {
    "@angular/animations": "^6.0.9",
    "@angular/cdk": "^6.4.0",
    "@angular/common": "^6.0.2",
    "@angular/compiler": "^6.0.2",
    "@angular/core": "^6.0.2",
    "@angular/forms": "^6.0.2",
    "@angular/http": "^6.0.2",
    "@angular/material": "^6.4.0",
    "@angular/platform-browser": "^6.0.2",
    "@angular/platform-browser-dynamic": "^6.0.2",
    "@angular/router": "^6.0.2",
    "core-js": "^2.5.4",
    "ol": "^5.1.3",
    "rxjs": "^6.0.0",
    "zone.js": "^0.8.26"
  },

那么,为什么我不导入 BrowserAnimationsModule 就一切正常,如果我导入它就会中断?我想使用 Angular Material,我需要它...

您必须使用 ngAfterViewInit,然后您可以 'sure' 您的组件模板中的元素出现在 DOM。

ngAfterViewInit() {
  this.map = new OlMap({
    target: 'map',
    layers: [new OlTileLayer({ source: new OlOSM() })],
    view: new OlView({ zoom: 13, center: fromLonLat([13.376935, 52.516181]) }),
    controls: []
  });
}

这是一个解决方案,

组件模板

<div #mapElementRef class="map"></div>

组件 class 实现 OnInit 并具有下一个 属性

@ViewChild('mapElementRef', { static: true }) mapElementRef: ElementRef;

最后在ngOnInit方法上初始化地图,可以使用

this.map.setTarget(this.mapElementRef.nativeElement);

希望对您有所帮助。

注意脏修复
我确实尝试了@cabesuon 的版本,但它仍然无法正常工作。

就像@cabueson 说的那样

<div #mapElementRef class="map"></div>

然后在你的component.ts,但是

  • 如@PoulKrujit 所说
  • ngAfterViewInit()
  • 添加 setTimeout(() => {}) 这是脏修复

这里是结果

export class MapBaseComponent implements AfterViewInit {
  @ViewChild('mapElementRef', { static: true }) mapElementRef: ElementRef

  map: OlMap

  constructor() {}

  ngAfterViewInit() {
    setTimeout(() => {
      this.map = new Map({
        layers: [new OlTileLayer({ source: new OlOSM() })],
        view: new OlView({ zoom: 13, center: fromLonLat([13.376935, 52.516181]) }),
        controls: [],
      })

      this.map.setTarget(this.mapElementRef.nativeElement)
    }, 0)
  }
}

我不是 100% 确定为什么,但这是我的猜测。
ion-content 实例化后不会刷新自己。但是,将代码置于超时强制 ion-content 下进行刷新。这也是为什么你不用放任何毫秒的原因。

强制 ionic 应用程序刷新的其他方法确实存在,例如 tick,但是超时对于我们在这里所做的事情来说已经足够了。

我遇到了类似的问题,但解决方法不同。让我和你分享我学到的东西。

我有一个 Angular (13) 应用程序,由于 router-outlet...所以我的应用程序看起来像这样:

// App.component.html
<router-outlet>

// App.route.module.ts
const routes: Routes = [
  { path: 'map-component', component: MapComponent },
  { path: 'settings', component: SettingsComponent },
];

map-component 是我的默认路线。所以当我启动我的应用程序时,一切都很好。

但是当我启用“设置”路由时,我的 MapComponent 被销毁,然后当我返回“map-component”时,在某些帧中我可以看到两个组件都出现在 DOM(如下面的屏幕截图所示):

所以我在地图组件中为解决这个问题所做的是以下代码:

// Map.component.ts

export class MapComponent implements AfterViewInit, DoCheck {
private previousHeight = 0;
@ViewChild('map') map!: ElementRef;


ngAfterViewInit(): void {
    this.previousHeight = this.map.nativeElement.offsetHeight;
    this.mapService.map.setTarget(this.map.nativeElement);
  }

  ngDoCheck(): void {
     if (this.map) {
      if(this.previousHeight !== this.map.nativeElement.offsetHeight) {
        this.previousHeight = this.map.nativeElement.offsetHeight;
        this.mapService.map.updateSize();
      }
    }
  }
}

因为Angular在动画过程中调用DoCheck方法,所以我在整个动画过程中更新了地图大小。

我对那个方法不是很满意。我真正想要的是禁用路由器动画(并保留所有其他动画)。 Buf 即使查看了 angular 文档,我也找不到关于这个“默认动画”的任何信息...