Ionic 4/5 - 带有服务的模态窗口中的谷歌地图

Posted

技术标签:

【中文标题】Ionic 4/5 - 带有服务的模态窗口中的谷歌地图【英文标题】:Ionic 4/5 - google maps in modal window with a service 【发布时间】:2021-08-22 11:28:00 【问题描述】:

我正在使用 javascript sdk 在 Ionic 5 中显示地图。 我使用为此创建的服务加载这些地图。

当我在页面中执行此操作时一切都很好,但如果我将其中一个页面显示为模式,则地图不会加载,并且标记将其放置在打开模式窗口的页面上,而不是在模式窗口本身中.

看看能不能把代码放在下面,这样就不会太“重”了

home.page.html

<ion-header [translucent]="true">
  <ion-toolbar>
    <ion-title>
      HOME
    </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content [fullscreen]="true">
    <div id="map"></div>
    <ion-button href = "page2" expand = "block">page 2</ion-button>
    <ion-button (click)="presentModal()" expand = "block" >page 3 modal</ion-button>
</ion-content>

page2.page.html

<ion-header>
  <ion-toolbar>
    <ion-title>page2</ion-title>
  </ion-toolbar>
</ion-header>

<ion-content>
    <div id="map"></div>
    <ion-button href = "home" expand = "block" >home</ion-button>
</ion-content>

page3.page.html

<ion-header>
  <ion-toolbar>
    <ion-title>page3</ion-title>
  </ion-toolbar>
</ion-header>
<ion-content>
    <div id="map"></div>
    <ion-button href = "home" expand = "block" >home</ion-button>
</ion-content>

home.page.ts

import  Component, OnInit             from '@angular/core';
import  ModalController               from '@ionic/angular';
import  LocationService           from 'src/app/services/Location.service'
import  Page3Page                     from 'src/app/pages/page3/page3.page';

@Component(
  selector: 'app-home',
  templateUrl: 'home.page.html',
  styleUrls: ['home.page.scss'],
)
export class HomePage 
    constructor(public LocationService: LocationService,
                public ModalController: ModalController) 

    ngOnInit () 
        this.LocationService.loadMap("home");
        

    async presentModal() 
        const modal = await this.ModalController.create(
            component: Page3Page
            );
        return await modal.present();
        

page2.page.ts

import  Component, OnInit  from '@angular/core';
import  LocationService       from 'src/app/services/Location.service'

@Component(
    selector: 'app-page2',
    templateUrl: './page2.page.html',
    styleUrls: ['./page2.page.scss'],
    )
export class Page2Page implements OnInit 
    constructor(private LocationService: LocationService) 

    ngOnInit () 
        //this.loadMap();
        this.LocationService.loadMap("page2");
        

page3.page.ts

import  Component, OnInit  from '@angular/core';
import  LocationService       from 'src/app/services/Location.service'

@Component(
  selector: 'app-page3',
  templateUrl: './page3.page.html',
  styleUrls: ['./page3.page.scss'],
)
export class Page3Page implements OnInit 
    constructor(private LocationService: LocationService) 

    ngOnInit() 
        this.LocationService.loadMap("page3");
        

location.service.ts

import  Injectable  from '@angular/core';

declare var google;

interface Marker 
    position: 
      lat: number,
      lng: number,
    ;
    title: string;
  

@Injectable(
  providedIn: 'root'
)
export class LocationService 

    map = null;

    constructor()  

    loadMap(prmtrMapId) 
        // create a new map by passing HTMLElement
        const mapEle: HTMLElement = document.getElementById('map');
        var myLatLng, myTitle;
        var marker;
        // create LatLng object
        switch (prmtrMapId) 
            case "home": // No hay sentencia "break" en el 'case 0:', por lo tanto este caso también será ejecutado
                myLatLng = lat: 54.1675272, lng: -7.5138625; //england
                myTitle = "home -> England";
                break; // Al encontrar un "break", no será ejecutado el 'case 2:'
            case "page2":
                myLatLng = lat: 51.713614, lng: 10.956151; //deutschland 
                myTitle = "page2 -> Deutschland ";
                break;
            case "page3":
                myLatLng = lat: 47.820012, lng: 3.490945; //france
                myTitle = "page3 modal -> France";
                break;
            default:
                myLatLng = lat: 4.658383846282959, lng: -74.09394073486328;
          
       
        marker = 
            position: myLatLng,
            title: myTitle
            ;

        // create map
        this.map = new google.maps.Map(mapEle, 
            center: marker.position,
            zoom: 4
            );

        google.maps.event.addListenerOnce(this.map, 'idle', () => 
            this.addMarker(marker);
        );
    

    addMarker(marker: Marker) 
    return new google.maps.Marker(
        position: marker.position,
        map: this.map,
        title: marker.title
    );
    


感谢任何帮助!

非常感谢

埃内斯托

【问题讨论】:

我认为,如果您打开模态对话框,您将使用 id 映射创建第二个 div。在您的服务中,您尝试获取可能是第一个的地图 id 元素。尝试重命名模态地图元素 id 并将其传递给服务。 【参考方案1】:

你可以使用 elementRef 并像这样传递它:

把服务改成这样:

loadMap(prmtrMapId, elRef: ElementRef) 
   const mapEle: HTMLElement = elRef.nativeElement;

在Page3中将html改为

<ion-content>
    <div #map></div>
    <ion-button href = "home" expand = "block" >home</ion-button>
</ion-content>

并在 ts 中添加 ViewChild 并像这样调用服务

@ViewChild('map') mapEl: ElementRef;

ngAfterViewInit()
   this.LocationService.loadMap("page3", this.mapEl);

因为“视图查询是在调用 ngAfterViewInit 回调之前设置的。”您需要使用 ngAfterViewInit 或 static: true。

https://angular.io/api/core/ViewChild#description

【讨论】:

是的,我在这里提出的问题是固定引用具有不同 id 的每个 div 谢谢,但我需要在生产应用程序中测试它,我会告诉你它是否有效,因为我想我尝试了那个解决方案并且它没有用。我会告诉你的 @Ernesto 非常感谢。您也可以尝试使用 ElementRef 作为参数,这样您就根本不必使用文档对象。像 一样,然后使用 \@ViewChild 装饰器来获取并传递该元素。如果你愿意,我可以相应地调整答案。 那太好了,我总是和 viewchild 搞混,所以我可以和他一起工作并习惯它,非常感谢@thecOdemOnkey @Ernesto 将答案更改为使用 ViewChild。它的干编码,但我认为它应该可以工作。 非常感谢@thecOdemOnkey 的帮助!【参考方案2】:

您能否检查(通过添加 console.log)是否在打开模式时触发:

ngOnInit() 
    this.LocationService.loadMap("page3");

     

【讨论】:

您好,是的,该指令已执行。发生的情况是,更改是在模态调用的页面地图中产生的,而不是在模态本身中产生的。位于法国的标记应出现在模态窗口中,并出现在打开模态的窗口中。在模态中,地图都没有加载。问候,埃内斯托 问题出在前一个用户提到的那一行,但我认为它是受控的,我测试得更深,我会告诉你

以上是关于Ionic 4/5 - 带有服务的模态窗口中的谷歌地图的主要内容,如果未能解决你的问题,请参考以下文章

如何从 ionic 2 中的谷歌地图获取纬度和经度?

保存要离线加载的谷歌地图图像

谷歌地图以Ionic 2中的模态显示

GeoComplete,模态中的谷歌地图显示灰色地图,位置仅在屏幕调整大小后显示

带有来自服务器的数字标记的谷歌地图

Chrome扩展弹出窗口中的谷歌图表?