Google 地图 API V3 之事件
Google官方教程:
概述
浏览器中的 JavaScript 是由事件驱动的,这表示 JavaScript 会通过生成事件来响应交互,并期望程序监听感兴趣的事件。Google Maps API V3 的事件模型与 Google Maps API V2 中所使用的事件模型尽管在内在机制上有很大的不同,但两者是十分相似的。有两种类型的事件:
- 用户事件(如“点击”鼠标事件)是从 DOM 传播到 Google Maps API 中的。这些事件是独立的,并且与标准 DOM 事件不同。
- MVC 状态更改通知反映了 Maps API 对象中的变化,并会根据
property_changed
惯例命名。
每个 Maps API 对象均可导出大量已命名的事件。如果程序想要实现某些事件,则会为这些事件注册 Javascript 事件监听器,并在 google.maps.event
命名空间中注册addListener()
事件处理程序,以便在接收这些事件后执行相应代码。Google Maps API V2 的开发者应该会熟悉此用法。
有关完整的事件列表,请参阅 Maps API 参考。对于包含事件的各个对象,我们在单独的部分中列出了这些对象的事件。
用户界面事件
Maps API 中的一些对象旨在对用户事件(例如鼠标事件或键盘事件)作出响应。google.maps.Marker
对象可以监听一些用户事件,例如:
'click'
'dblclick'
'mouseup'
'mousedown'
'mouseover'
'mouseout'
这些事件可能看上去像是标准 DOM 事件,但实际上却是 Maps API 的一部分。由于不同的浏览器所实现的 DOM 事件模型并不相同,因此,Maps API 提供了用于监听和响应这些 DOM 事件的机制,该机制无需处理各种跨浏览器特性。这些事件通常还会在表明某些用户界面状态(例如鼠标位置)的事件中传递参数。
MVC 状态更改
MVC 对象通常都包含状态。只要更改了对象的属性,API 就会触发已更改该属性的事件。例如,当地图的缩放级别更改后,API 将会触发地图上的 zoom_changed
事件。您也可以在 event
命名空间方法中注册 addListener()
事件处理程序,以拦截这些状态更改。
用户事件和 MVC 状态更改看上去很相似,但通常情况下,您应该在代码中对它们进行不同的处理。例如,MVC 事件不在其事件中传递参数。您可能需要调用该对象上的相应 getProperty
方法,以检查 MVC 状态更改中所更改的属性。
地图事件
您可以使用 addListener()
事件处理程序注册接收事件通知。该方法采用了一个对象、一个待监听事件以及一个用于在指定事件发生时调用的函数。
以下代码可将用户事件和状态更改事件进行组合。我们可将事件处理程序附加到点击时对地图执行缩放操作的标记上。我们还会向地图添加事件处理程序以更改“center”属性,并在接收 center_changed
事件的 3 秒后将地图平移回标记处:
function initialize() {
var mapOptions = {
zoom: 4,
center: new google.maps.LatLng(-25.363882, 131.044922),
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
var marker = new google.maps.Marker({
position: map.getCenter(),
map: map,
title: 'Click to zoom'
});
google.maps.event.addListener(map, 'center_changed', function() {
// 3 seconds after the center of the map has changed, pan back to the
// marker.
window.setTimeout(function() {
map.panTo(marker.getPosition());
}, 3000);
});
google.maps.event.addListener(marker, 'click', function() {
map.setZoom(8);
map.setCenter(marker.getPosition());
});
}
google.maps.event.addDomListener(window, 'load', initialize);
提示:如果您要尝试检测视口中的变化,请务必使用特定的 bounds_changed
事件,而非其组成部分 zoom_changed
和 center_changed
事件。由于 Maps API 会单独触发后面的两个事件,因此,只有在系统强制更改了视口后,getBounds()
才会报告实用结果。如果您想要在此类事件之后获得 getBounds()
,请务必改为监听 bounds_changed
事件。
访问用户界面事件中的参数
通常情况下,Google Maps API V3 中的用户界面事件会传递事件参数,您可通过事件监听器访问该参数(其中注明了事件发生时的用户界面状态)。例如,用户界面'click'
事件通常会传递一个包含 latLng
属性的 MouseEvent
,该属性指示了地图上的点击位置。请注意,这是用户界面事件所独有的行为;MVC 状态更改不会在其事件中传递参数。
您可以采用与访问对象属性一样的方法来访问事件监听器中的事件参数。以下示例介绍了如何为地图添加事件监听器,以及如何当用户点击地图时在所点击的位置创建一个标记。
var map;
function initialize() {
var myLatlng = new google.maps.LatLng(-25.363882,131.044922);
var mapOptions = {
zoom: 4,
center: myLatlng,
mapTypeId: google.maps.MapTypeId.ROADMAP
}
map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
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 mapOptions = { zoom: 4, center: myLatlng, mapTypeId: google.maps.MapTypeId.ROADMAP } map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions); // 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); });
获取和设置事件处理程序中的属性
Maps API 事件系统中没有任何 MVC 状态更改事件会在事件触发时传递参数。(用户事件确实会传递参数,这是可以检查到的。)如果您需要检查有关 MVC 状态更改的属性,应在该对象上显式调用相应的 getProperty()
方法。在此检查过程中,系统会始终检索 MVC 对象的当前状态,不过该状态可能不是 MVC 对象在首次触发相应事件时所处的状态。
注意:在对特定属性的状态更改作出响应的事件处理程序中显式设置一个属性,可能会产生不可预期和/或不必要的行为。例如,设置此类属性将会触发新的事件,而且如果您总是在此事件处理程序中设置属性,那么最终可能会出现无限循环的情况。
在以下示例中,我们会设置一个事件处理程序,使其通过构建显示缩放级别的信息窗口对缩放事件作出响应。
function initialize() {
var myLatLng = new google.maps.LatLng(-25.363882, 131.044922);
var mapOptions = {
zoom: 4,
center: myLatLng,
mapTypeId: google.maps.MapTypeId.ROADMAP
};
var map = new google.maps.Map(document.getElementById('map_canvas'),
mapOptions);
var infowindow = new google.maps.InfoWindow({
content: 'Change the zoom level',
position: myLatLng
});
infowindow.open(map);
google.maps.event.addListener(map, 'zoom_changed', function() {
var zoomLevel = map.getZoom();
map.setCenter(myLatLng);
infowindow.setContent('Zoom: ' + zoomLevel);
});
}
google.maps.event.addDomListener(window, 'load', initialize);
监听 DOM 事件
Google Maps JavaScript API 事件模型会自行创建并管理自定义事件。不过,浏览器内的 DOM(文档对象模型)也会根据所使用的特定浏览器事件模型自行创建并分派事件。如果您想要捕获并响应这些事件,可以使用 Maps API 提供的 addDomListener()
静态方法来监听并绑定到这些 DOM 事件。
该方法易于使用,且具有如下所示的签名:
其中 instance
可能是浏览器支持的任意 DOM 元素,包括:
- DOM 的分层组成部分,例如
window
或document.body.myform
- 已命名的元素,例如
document.getElementById("foo")
请注意,addDomListener()
只是将指明的事件传递给浏览器,以便系统根据浏览器的 DOM 事件模型来处理该事件;不过,几乎所有的热门浏览器都至少支持 DOM 级别 2。(有关 DOM 级别事件的详情,请参阅 Mozilla DOM 级别参考。)
看到这里,您可能已经熟悉了 window.onload
这一 DOM 事件,我们已在 <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 与其常规域之外的对象进行通信。