Google Maps 现已成为 Angular 组件的赢家

2025-05-27

Google Maps 现在是 Angular 组件

获胜

新的 Angular 组件pearl-lullaby (v9.0.0-rc.0)引入了第二个官方@angular/component组件:Google Maps 组件。
在本文中,我们将学习如何开始使用 Google Maps 组件。

今年早些时候,我们将此代码库的名称更改为“angular/components”,以强调我们
提供的不仅仅是 Material Design 组件的目标。9.0.0 版本包含了这方面的一项新功能——一个将Google Maps JavaScript API包装在一个易于使用的 Angular 组件中的
新软件包。

我非常期待团队能够扩展代码库来创建组件。
我们已经在v8.2.0中看到了一个YouTube Player组件, Craig文章中对此进行了探讨

这些与现有 JavaScript API 的新集成使我们的工作变得更加轻松,
我很好奇即将发布的其他新组件!

设置

角度

可以从 安装 Google 地图模块@angular/google-maps

npm install @angular/google-maps
Enter fullscreen mode Exit fullscreen mode

安装完成后,我们必须将 Angular 模块添加GoogleMapsModuleimport声明中。

import { BrowserModule } from '@angular/platform-browser'
import { NgModule } from '@angular/core'
import { GoogleMapsModule } from '@angular/google-maps'

import { AppComponent } from './app.component'

@NgModule({
  declarations: [AppComponent],
  imports: [BrowserModule, GoogleMapsModule],
  providers: [],
  bootstrap: [AppComponent],
})
export class AppModule {}
Enter fullscreen mode Exit fullscreen mode

导出GoogleMapsModule我们可以使用的三个组件:

  • GoogleMap:这是 Google 地图的包装器,可通过google-map选择器获取
  • MapMarker:用于在地图上添加标记,可通过map-marker选择器使用
  • MapInfoWindow:标记的信息窗口,可通过map-info-window选择器访问

加载 Maps JavaScript API

我们还必须导入 Maps API,这可以通过在index.html文件中添加脚本标签来完成。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="utf-8" />
    <title>Map</title>
    <base href="/" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
    <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY"></script>
  </head>
  <body>
    <app-root></app-root>
  </body>
</html>
Enter fullscreen mode Exit fullscreen mode

要在生产环境中使用地图,您需要创建一个新的 API 密钥,请按照文档创建一个新密钥。

用法

谷歌地图

通过将 Google 地图组件添加到模板,我们就可以查看并使用 Google 地图了。
该地图将作为默认地图使用,并具有默认功能,例如,您可以放大、缩小地图并在地图中拖动。

<google-map></google-map>
Enter fullscreen mode Exit fullscreen mode

谷歌地图截图

输入属性

我们可以使用属性自定义默认地图的样式@Input()
最常用的属性已添加为@Input属性,我们可以设置地图的大小、设置中心以及设置缩放级别。

财产 描述
height 设置初始高度
width 设置初始宽度
center 设置初始中心
zoom 设置初始缩放
options 设置选项,更多信息请参阅文档

为了充分利用 Google Maps API,我们还可以使用options属性。
使用显式属性比使用 属性更胜一筹options
属性options具有与 相同的接口Map Options interface

<google-map
  height="500px"
  width="100%"
  [zoom]="zoom"
  [center]="center"
  [options]="options"
></google-map>

<!-- Use custom zoom buttons -->
<button (click)="zoomIn()">Zoom in</button>
<button (click)="zoomOut()">Zoom out</button>
Enter fullscreen mode Exit fullscreen mode
export class AppComponent implements OnInit {
  zoom = 12
  center: google.maps.LatLngLiteral
  options: google.maps.MapOptions = {
    mapTypeId: 'hybrid',
    zoomControl: false,
    scrollwheel: false,
    disableDoubleClickZoom: true,
    maxZoom: 15,
    minZoom: 8,
  }

  ngOnInit() {
    navigator.geolocation.getCurrentPosition(position => {
      this.center = {
        lat: position.coords.latitude,
        lng: position.coords.longitude,
      }
    })
  }

  zoomIn() {
    if (this.zoom < this.options.maxZoom) this.zoom++
  }

  zoomOut() {
    if (this.zoom > this.options.minZoom) this.zoom--
  }
}
Enter fullscreen mode Exit fullscreen mode

定制版谷歌地图截图

输出属性

GoogleMap组件将所有 Google Maps API 事件公开为@Output()属性:

财产 JavaScript API 方法 描述
boundsChanged bounds_changed 当视口边界发生变化时,会触发此事件
centerChanged center_changed 地图中心属性改变时触发此事件
mapClick click 当用户点击地图时触发此事件
mapDblclick dblclick 用户双击地图时会触发此事件。请注意,在此事件之前,click 事件也会触发。
mapDrag drag 当用户拖动地图时,此事件会重复触发
mapDragend dragend 当用户停止拖动地图时触发此事件
mapDragstart dragstart 当用户开始拖动地图时触发此事件
headingChanged heading_changed 地图标题属性发生改变时触发此事件
idle idle 地图平移或缩放后变为空闲状态时触发此事件
maptypeidChanged maptypeid_changed 当 mapTypeId 属性发生改变时触发此事件
mapMousemove mousemove 每当用户的鼠标移动到地图容器上时,就会触发此事件
mapMouseout mouseout 当用户的鼠标退出地图容器时触发此事件
mapMouseover mouseover 当用户的鼠标进入地图容器时触发此事件
projectionChanged projection_changed 当投影发生变化时触发此事件
mapRightclick rightclick 当地图容器上触发 DOM contextmenu 事件时,将触发此事件
tilesloaded tilesloaded 当可见图块加载完成时触发此事件
tiltChanged tilt_changed 地图倾斜属性改变时触发此事件
zoomChanged zoom_changed 地图缩放属性改变时触发此事件

一篇文章涵盖所有这些事件可能过于冗长,本文我们将逐一介绍这些click()事件。
如果您对所有事件感兴趣,我建议您参阅Google Maps API 文档,查看完整列表以及 Angular 源代码中的实现

<google-map (mapClick)="click($event)"></google-map>
Enter fullscreen mode Exit fullscreen mode
export class AppComponent implements OnInit {
  click(event: google.maps.MouseEvent) {
    console.log(event)
  }
}
Enter fullscreen mode Exit fullscreen mode
方法和 getter

如果我们通过使用装饰器保留对地图组件的引用@ViewChild,我们还可以使用以下方法和 getter。

功能 描述
fitBounds 设置视口以包含给定的边界
panBy 将地图中心改变给定的像素距离
panTo 将地图中心更改为给定的 LatLng
panToBounds 将地图平移至包含给定 LatLngBounds 所需的最小量
getBounds 返回当前视口的纬度/经度边界
getCenter 返回地图中心显示的位置
getClickableIcons 返回地图图标的可点击性
getHeading 返回航空图像的罗盘航向
getMapTypeId 返回地图类型 ID
getProjection 返回当前投影
getStreetView 返回绑定到地图的默认StreetViewPanorama,可能是地图内嵌入的默认全景图
getTilt 返回地图的当前入射角,以从视口平面到地图平面的度数为单位
getZoom 返回当前缩放比例
controls 附加到地图的附加控件
data 绑定到地图的数据实例
mapTypes 通过字符串 ID 注册 MapType 实例
overlayMapTypes 可叠加的其他地图类型

例如,我们可以记录地图的当前中心。

export class AppComponent implements OnInit {
  @ViewChild(MapInfoWindow, { static: false }) info: MapInfoWindow

  logCenter() {
    console.log(JSON.stringify(this.map.getCenter()))
  }
}
Enter fullscreen mode Exit fullscreen mode

地图标记

输入属性

地图设置好后,我们就可以开始添加标记了。
这可以通过使用MapMarker组件来完成。
要添加标记,请确保标记位于google-map标签内,否则将不会显示。

就像 一样MapControl,最常用的选项可以直接通过@Input()属性设置,但也可以使用 的完整选项集MapMarker

<google-map>
  <map-marker
    *ngFor="let marker of markers"
    [position]="marker.position"
    [label]="marker.label"
    [title]="marker.title"
    [options]="marker.options"
  >
  </map-marker>
</google-map>
Enter fullscreen mode Exit fullscreen mode
export class AppComponent implements OnInit {
  addMarker() {
    this.markers.push({
      position: {
        lat: this.center.lat + ((Math.random() - 0.5) * 2) / 10,
        lng: this.center.lng + ((Math.random() - 0.5) * 2) / 10,
      },
      label: {
        color: 'red',
        text: 'Marker label ' + (this.markers.length + 1),
      },
      title: 'Marker title ' + (this.markers.length + 1),
      options: { animation: google.maps.Animation.BOUNCE },
    })
  }
}
Enter fullscreen mode Exit fullscreen mode

带有标记的 Google 地图的屏幕截图

该标记的完整规格:

财产 描述
title 设置标题,悬停时可见
position 设置位置
label 设置标签
clickable 如果标记应该监听鼠标和触摸事件,则默认为true
options 设置选项,更多信息请参阅文档

输出属性

MapMarker组件还将 Google Maps API 事件作为@Output()属性公开:

财产 JavaScript API 方法 描述
animationChanged animation_changed 当标记的动画属性发生改变时,会触发此事件
mapClick click 单击标记图标时会触发此事件
clickableChanged clickable_changed 当标记的光标属性发生改变时,会触发此事件
cursorChanged cursor_changed 当标记的光标属性发生改变时,会触发此事件
mapDblclick dblclick 双击标记图标时触发此事件
mapDrag drag 当用户拖动标记时,此事件会重复触发
mapDragend dragend 当用户停止拖动标记时触发此事件
draggableChanged draggable_changed 当标记的可拖动属性发生改变时,会触发此事件
mapDragstart dragstart 当用户开始拖动标记时触发此事件
flatChanged flat_changed 当标记的平面属性发生变化时,会触发此事件
iconChanged icon_changed 当标记图标属性发生改变时,会触发此事件
mapMousedown mousedown 当鼠标按下标记时触发此事件
mapMouseout mouseout 当鼠标离开标记图标区域时触发此事件
mapMouseover mouseover 当鼠标进入标记图标区域时触发此事件
mapMouseup mouseup 当鼠标悬停在标记上时触发此事件
positionChanged position_changed 当标记位置属性发生改变时,会触发此事件
mapRightclick rightclick 右键单击标记时触发此事件
shapeChanged shape_changed 当标记的形状属性发生变化时,会触发此事件
titleChanged title_changed 当标记标题属性发生改变时,会触发此事件
visibleChanged visible_changed 当标记的 visible 属性发生改变时,会触发此事件
zindexChanged zindex_changed 当标记的 zIndex 属性发生改变时,会触发此事件

可以在Google Maps API 文档中找到对 API 的完整引用,并在源代码中找到 Angular 实现

地图信息窗口

最后一个组件是MapInfoWindow,它可以用来打开标记的弹出窗口。
要显示弹出窗口,我们必须在google-map模板中添加该组件。

<map-info-window>Hello Google Maps</map-info-window>
Enter fullscreen mode Exit fullscreen mode

上面的代码什么也没做,为了让它看起来就像点击标记时打开信息窗口一样。
我们将mapClick()方法绑定到标记,并将标记引用传递给openInfo方法以打开信息窗口。

<map-marker
  #markerElem
  *ngFor="let marker of markers"
  [position]="marker.position"
  [label]="marker.label"
  [title]="marker.title"
  [options]="marker.options"
  (mapClick)="openInfo(markerElem)"
>
</map-marker>
Enter fullscreen mode Exit fullscreen mode

MapInfoWindow最后,我们在组件内部也有一个对组件的引用。
我们可以通过使用@ViewChild装饰器来实现这一点。
有了信息窗口和标记的引用,我们就可以使用该infoWindow.open()方法打开信息窗口了。

export class AppComponent implements OnInit {
  @ViewChild(MapInfoWindow, { static: false }) infoWindow: MapInfoWindow

  openInfo(marker: MapMarker, content) {
    this.infoWindow.open(marker)
  }
}
Enter fullscreen mode Exit fullscreen mode
输入属性
财产 描述
options 设置选项,更多信息请参阅文档
输出属性
财产 JavaScript API 方法 描述
closeclick closeclick 单击关闭按钮时触发此事件
contentChanged content_changed 当内容属性发生改变时触发此事件
domready domready <div>当包含信息窗口内容的附加到 DOM时,会触发此事件
positionChanged position_changed 当位置属性改变时触发此事件
zindexChanged zindex_changed 当信息窗口的 zIndex 发生变化时,会触发此事件

方法和 getter

通过使用infoWindow具有对MapInfoWindow组件的引用的属性,我们可以使用其以下方法和 getter

财产 描述
close 通过从 DOM 结构中移除此信息窗口来关闭它
getContent 返回信息窗口的内容
getPosition 返回信息窗口的位置
getZIndex 返回信息窗口的 z 索引
open 使用提供的 MapMarker 作为锚点打开 MapInfoWindow。如果未设置锚点,则使用选项输入的position属性。
动态内容

信息窗口内显示静态内容略显单调。
为了在信息窗口内提供动态内容,我们可以在组件内创建一个字符串属性,如下所示。

<map-info-window>{{ infoContent }}</map-info-window>
Enter fullscreen mode Exit fullscreen mode
export class AppComponent implements OnInit {
  @ViewChild(MapInfoWindow, { static: false }) infoWindow: MapInfoWindow
  infoContent = ''

  openInfo(marker: MapMarker, content) {
    this.infoContent = content
    this.infoWindow.open(marker)
  }
}
Enter fullscreen mode Exit fullscreen mode

可以在Google Maps API 文档中找到对 API 的完整引用,并在源代码中找到 Angular 实现

整合起来

即将发布的 Angular 版本将为我们带来一系列积极的变化和全新的可能性。
我们早已翘首以盼 Angular v9 中的 Ivy 版本,现在我们也将共同期待 的新版本@angular/components

除了新功能之外MapComponent,还将与 Angular CDK 中的剪贴板 API 进行集成,如使用新的 Angular Clipboard CDK 与剪贴板交互中所述。

Angular 组件非常新,因此文档和示例代码非常少。由于 Angular 的实现遵循 Google Maps API 规范,我们可以从 JavaScript API 中
查看丰富的文档。

请参阅下面的代码来了解此帖子的完整探索示例。

<google-map
  height="500px"
  width="100%"
  [zoom]="zoom"
  [center]="center"
  [options]="options"
  (mapClick)="click($event)"
>
  <map-marker
    #markerElem
    *ngFor="let marker of markers"
    [position]="marker.position"
    [label]="marker.label"
    [title]="marker.title"
    [options]="marker.options"
    (mapClick)="openInfo(markerElem, marker.info)"
  >
  </map-marker>

  <map-info-window>{{ infoContent }}</map-info-window>
</google-map>

<button (click)="zoomIn()">Zoom in</button>
<button (click)="zoomOut()">Zoom out</button>
<button (click)="logCenter()">Log center</button>
<button (click)="addMarker()">Add marker</button>
Enter fullscreen mode Exit fullscreen mode
import { Component, OnInit, ViewChild } from '@angular/core'
import { MapInfoWindow, MapMarker, GoogleMap } from '@angular/google-maps'

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent implements OnInit {
  @ViewChild(GoogleMap, { static: false }) map: GoogleMap
  @ViewChild(MapInfoWindow, { static: false }) info: MapInfoWindow

  zoom = 12
  center: google.maps.LatLngLiteral
  options: google.maps.MapOptions = {
    zoomControl: false,
    scrollwheel: false,
    disableDoubleClickZoom: true,
    mapTypeId: 'hybrid',
    maxZoom: 15,
    minZoom: 8,
  }
  markers = []
  infoContent = ''

  ngOnInit() {
    navigator.geolocation.getCurrentPosition(position => {
      this.center = {
        lat: position.coords.latitude,
        lng: position.coords.longitude,
      }
    })
  }

  zoomIn() {
    if (this.zoom < this.options.maxZoom) this.zoom++
  }

  zoomOut() {
    if (this.zoom > this.options.minZoom) this.zoom--
  }

  click(event: google.maps.MouseEvent) {
    console.log(event)
  }

  logCenter() {
    console.log(JSON.stringify(this.map.getCenter()))
  }

  addMarker() {
    this.markers.push({
      position: {
        lat: this.center.lat + ((Math.random() - 0.5) * 2) / 10,
        lng: this.center.lng + ((Math.random() - 0.5) * 2) / 10,
      },
      label: {
        color: 'red',
        text: 'Marker label ' + (this.markers.length + 1),
      },
      title: 'Marker title ' + (this.markers.length + 1),
      info: 'Marker info ' + (this.markers.length + 1),
      options: {
        animation: google.maps.Animation.BOUNCE,
      },
    })
  }

  openInfo(marker: MapMarker, content) {
    this.infoContent = content
    this.info.open(marker)
  }
}
Enter fullscreen mode Exit fullscreen mode

在 Twitter 上关注我@tim_deschryver | 最初发布于timdeschryver.dev

文章来源:https://dev.to/angular/google-maps-is-now-an-angular-component-2pjb
PREV
使用战术 DDD 和 MonoRepos 实现可持续的 Angular 架构?
NEXT
在部署任何网站之前在 CI 中运行很好的测试还有其他的吗?