Google Maps JavaScript API V3 事件
地图事件概述
浏览器中的 JavaScript 是事件驱动的,这表示 JavaScript 通过生成事件来响应交互,并期望程序侦听感兴趣的事件。Google Maps API 第 3 版的事件模型与 Google Maps API 第 2 版中所使用的事件模型在内在机制上尽管有很大的不同,但两者是十分相似的。有两种类型的事件:
- 用户事件(如“点击”鼠标事件)是从 DOM 传播到 Google Maps API 中的。这些事件是独立的,并且与标准 DOM 事件不同。
- MVC 状态更改通知反映了 Google Maps API 对象中的更改,并以
property_changed
惯例命名
每个 Google Maps API 对象都可导出大量已命名的事件。如果程序想要实现某些事件,则会为这些事件注册 Javascript 事件侦听器,并会在通过在 google.maps.event
命名空间中注册 addListener()
事件处理程序接收这些事件时执行相应的代码。Google Maps API 第 2 版的开发人员应该会熟悉这一用法。
有关事件的完整列表,请参见 Google Maps API 参考。至于包含事件的各个对象,我们在单独的部分中列出了这些对象的事件。
用户界面事件
Google Maps API 中的一些对象旨在对用户事件(例如鼠标事件或键盘事件)作出响应。google.maps.Marker
对象可以侦听以下用户事件,例如:
-
'click'
-
'dblclick'
-
'mouseup'
-
'mousedown'
-
'mouseover'
-
'mouseout'
这些事件可能看上去像是标准 DOM 事件,但实际上却是 Google Maps API 的一部分。由于不同的浏览器可实现不同的 DOM 事件模型,因此,Google Maps API 提供了无需处理各种跨浏览器特性便可侦听和响应 DOM 事件的机制。这些事件通常还会在表明某些用户界面状态(例如鼠标位置)的事件中传递参数。
MVC 状态更改
MVC 对象通常都有相应的状态。只要更改了对象的属性,那么,API 就会触发已更改该属性的事件。例如,当地图的缩放级别更改后,API 将会触发地图上的 zoom_changed
事件。您也可以通过在 event
命名空间方法中注册 addListener()
事件处理程序的方式截获这些状态更改。
用户事件和 MVC 状态更改看上去很相似,但通常情况下,您应该在代码中对它们进行不同的处理。例如,MVC 事件不在它们的事件中传递参数。您可能需要通过调用该对象上相应的 getProperty
方法,检查在 MVC 状态更改中更改的属性。
地图事件
您可使用 addListener()
事件处理程序注册以接收事件通知。该方法有三个参数,一个对象,一个待侦听事件以及一个在指定事件发生时调用的函数。
以下代码可将用户事件和状态更改事件进行组合。我们可将事件处理程序附加到点击时对地图执行缩放操作的标记上。我们还针对“zoom”属性的更改在地图中添加了事件处理程序,并在收到 zoom_changed
事件时将地图移动到澳大利亚北领地的达尔文市:
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var myOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'zoom_changed', function() {
setTimeout(moveToDarwin, 3000);
});
var marker = new google.maps.Marker({
position: myLatlng,
map: map,
title:"Hello World!"
});
google.maps.event.addListener(marker, 'click', function() {
map.setZoom(8);
});
}
function moveToDarwin() {
var darwin = new google.maps.LatLng(-12.461334, 130.841904);
map.setCenter(darwin);
}
请注意:如果您要尝试检测视口中的更改,请务必使用特定的 bounds_changed
事件,而不要使用作为其组成部分的 zoom_changed
和 center_changed
事件。由于 Google Maps API 会单独触发后面的两个事件,因此,只有在系统强制性地更改了视口后,getBounds()
才能报告有用的结果。如果您想要在此类事件之后实现 getBounds()
方法,请务必侦听bounds_changed
事件。
访问用户界面事件中的参数
通常情况下,Google Maps API 第 3 版中的用户界面事件会传递事件参数,您可通过事件侦听器访问这些参数,这些参数会注明事件发生时用户界面所处的状态。例如,用户界面'click'
事件通常传递包含 latLng
属性的 MouseEvent
,该属性指出了地图上的点击位置。请注意,这是用户界面事件所独有的行为;MVC 状态更改不会在它们的事件中传递参数。
您可以访问事件侦听器中的事件参数,这与访问对象属性的方法一样。以下示例介绍了如何为地图添加事件侦听器,以及如何在用户点击地图时,在所点击的位置处创建一个标记。
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var myOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
google.maps.event.addListener(map, 'click', function(event) {
placeMarker(event.latLng);
});
}
function placeMarker(location) {
var marker = new google.maps.Marker({
position: location,
map: map
});
map.setCenter(location);
}
在事件侦听器中使用闭包
在执行事件侦听器时,通常可取的做法是将私有数据和持久性数据附加到对象中。JavaScript 不支持“私有”实例数据,但它支持允许内部函数访问外部变量的闭包。在事件侦听器访问通常不附加到发生事件的对象的变量时,闭包非常有用。
下例在事件侦听器中使用函数闭包将加密消息分配给一组标记。点击每个标记都可以看到加密消息的一部分,该消息并未包含在标记自身内。
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var myOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
// Add 5 markers to the map at random locations
var southWest = new google.maps.LatLng(-31.203405,125.244141);
var northEast = new google.maps.LatLng(-25.363882,131.044922);
var bounds = new google.maps.LatLngBounds(southWest,northEast);
map.fitBounds(bounds);
var lngSpan = northEast.lng() - southWest.lng();
var latSpan = northEast.lat() - southWest.lat();
for (var i = 0; i < 5; i++) {
var location = new google.maps.LatLng(southWest.lat() + latSpan * Math.random(),
southWest.lng() + lngSpan * Math.random());
var marker = new google.maps.Marker({
position: location,
map: map
});
var j = i + 1;
marker.setTitle(j.toString());
attachSecretMessage(marker, i);
}
}
// The five markers show a secret message when clicked
// but that message is not within the marker's instance data
function attachSecretMessage(marker, number) {
var message = ["This","is","the","secret","message"];
var infowindow = new google.maps.InfoWindow(
{ content: message[number],
size: new google.maps.Size(50,50)
});
google.maps.event.addListener(marker, 'click', function() {
infowindow.open(map,marker);
});
}
获取和设置事件处理程序中的属性
在系统触发事件时,Google Maps API 事件系统中的任何 MVC 状态更改事件都不会传递参数(用户事件确实会传递参数,这是可以检查到的)。如果您需要检查有关 MVC 状态更改的某一属性,则应当显式的调用该对象上相应的 getProperty()
方法。在此检查过程中,系统会始终检索 MVC 对象的“当前状态”,但这一状态可能不是 MVC 对象在首次触发相应事件时所处的状态。
请注意:在对“特定属性”的状态更改作出响应的事件处理程序中,显式设置一个属性可能会产生不可预期的和/或不必要的行为。例如,设置此类属性将会触发新的事件,而且,如果您总是在此事件处理程序中设置属性,那么,您最终可能会出现无限循环的情况。
在以下示例中,我们会设置一个事件处理程序,使其通过构建显示缩放级别的信息窗口对缩放事件作出响应。我们还会检查地图是否已完全缩小,如果是的话,我们会将地图放大到缩放级别 17。
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var myOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), myOptions);
var zoomLevel;
var infowindow = new google.maps.InfoWindow(
{ content: 'Zoom Level Test',
size: new google.maps.Size(50,50),
position: myLatlng
});
infowindow.open(map);
google.maps.event.addListener(map, 'zoom_changed', function() {
zoomLevel = map.getZoom();
infowindow.setContent("Zoom: " + zoomLevel);
if (zoomLevel == 0) {
map.setZoom(10);
}
});
}
监听 DOM 事件
Google Maps JavaScript API 事件模型会自行创建并管理自定义事件。然而,浏览器内的 DOM(文档对象模型)也会根据所使用的特定浏览器事件模型自行创建并分派事件。如果您希望捕获并响应这些事件,则可使用 Maps API 提供的 addDomListener()
静态方法来监听并绑定这些 DOM 事件。
该方法易于使用,并且拥有如下所示的签名:
addDomListener(instance:Object, eventName:string, handler:Function)
其中 instance
可能是浏览器支持的任意 DOM 元素,包括:
- DOM 的分层组成部分,如
window
或document.body.myform
- 指定的元素,如
document.getElementById("foo")
请注意:addDomListener()
只是将指明的事件传递给浏览器,这样系统会按照浏览器的 DOM 事件模型来处理该事件;然而,几乎所有的热门浏览器都至少支持 DOM 级别 2(关于 DOM 级别事件的详情,请参见 Mozilla DOM 级别参考)。
看到这里,您可能已经熟悉了一个 DOM 事件:window.onload
事件,我们已在 <body>
标记内对其进行了处理。我们使用该事件在 HTML 页面完全加载后触发初始的 JavaScript 代码,具体如下:
<script>
function initialize() {
// Map initialization
}
</script>
<body onload="initialize()">
<div id="map_canvas"></div>
</body>
尽管此处将该事件附加到了 <body>
元素上,但实际上该事件为 window
事件,表明 window
元素下的 DOM 分层已经全部构建并呈现完毕。
将 onload
事件放置在 <body>
标记内虽然易于理解,但会将内容与行为混淆起来。一般来说,较好的做法是将内容代码 (HTML) 与行为代码 (JavaScript) 分隔开来,同时单独提供显示代码 (CSS)。要实现此目的,您可以将自己的 Maps API JavaScript 代码中的内嵌 onload
事件处理程序替换为 DOM 监听器,如下所示:
<script>
function initialize() {
// Map initialization
}
google.maps.event.addDomListener(window, 'load', initialize);
</script>
<body>
<div id="map_canvas"></div>
</body>
尽管上述代码为 Maps JavaScript API 代码,但 addDomListener()
方法会绑定到浏览器的 window
对象,并允许该 API 与其常规域之外的对象进行通信。