百度地图API详解之事件机制

一次调试百度地图多marker事件监听的问题,不知如何解决,后来看了原作者jz1108才知道要用闭包。觉得原作者jz1108关于百度地图的文章写的不错,所以转载到了CSDN,为了尊重原作者jz1108,特此说明。

 

和DOM编程里的事件模型一样,百度地图API也提供了类似的事件机制。本文介绍了事件监听的添加和移除方法,this指针和事件参数的使用以及绑定事件监听函数中涉及的闭包问题,最后分享了一个用来增强地图API事件机制的开源项目


事件添加和移除

我们最简单的事件开始,下面的代码示例给map对象添加了click事件的监听函数,当用户点击地图时该监听函数就会被触发:

var map =new BMap.Map('map');
map.centerAndZoom(new BMap.Point(116.404, 39.915), 11);

map.addEventListener('click', function(){
    alert('您点击了地图');
});

在初始化地图完成后,我们通过map对象的addEventListener方法添加click事件的监听。凡是在类参考文档中说明某个类具备某些事件时,我们都可以调用该对象的addEventListener方法添加响应的事件监听函数。

上面我们通过传入一个匿名函数添加了事件监听,如果我们需要移除事件监听,则需要将监听函数用具名函数表示:

复制代码
var clickHandler =function(){
    alert('您点击了地图');
}

map.addEventListener('click', clickHandler);

// 后续进行移除
map.removeEventListener('click', clickHandler);
复制代码


事件参数

和DOM事件类似,在百度地图API的事件机制中也提供了事件参数,参数通过监听函数的参数进行传递,比如我们修改最开始的代码:

map.addEventListener('click', function(e){
    alert('点击坐标: '+ e.point.lng +', '+ e.point.lat);
});

通过API的类参考文档得知,click事件的参数包含type、target、point和pixel四个属性,上面的示例就是获取了point属性,它表示当前点击的地理位置。


this

在事件监听中还可以通过this引用触发事件的对象,就像标准的DOM事件一样。

map.addEventListener('dragend', function(e){
    alert(this.getCenter());  // 这里的this就是map实例
});


事件闭包

闭包是JavaScript脚本语言的特性之一,不熟悉它的开发者很可能犯下面这种错误:页面有十个标注(Marker实例),我希望点击不同的标注开启内容不同的信息窗口,每个信息窗口显示该标注的索引(1到10)。首先我们初始化标注实例并存放于数组中:

var markers = [];
for (var i =0; i <10; i ++) { var mkr =new BMap.Marker(new BMap.Point(116.2+ i /20, 39.855), {title: i +1}); markers.push(mkr); map.addOverlay(mkr);
}

我们给每个标注添加自己的title属性以示区分,你将看到如下效果:

下面,我们添加标注的点击事件,用来开启内容不同的信息窗口:

for (i =0; i <10; i ++) {
    markers[i].addEventListener('click', function(){
        this.openInfoWindow(new BMap.InfoWindow('我是第'+ (i +1) +'个标注'));
    });
}

代码看起来没有任何问题,循环遍历markers数组,为每个标注实例绑定click事件,事件处理函数中开启信息窗口并显示是第几个标注。但是通过浏览器看效果的时候却发现问题了:

明明是第三个标注,点击之后的信息窗口中却显示“11”。实际上,当click的监听函数被执行的时候才会去看变量i的值是什么,此时for循环早已经执行完,那么当for循环执行完i的值正好是11。为了达到我们想要的效果,需要增加一层“闭包”:

复制代码
for (i =0; i <10; i ++) {
    (function(){
        var index = i;
        markers[i].addEventListener('click', function(){
            this.openInfoWindow(new BMap.InfoWindow('我是第'+ (index +1) +'个标注'));
        });    
    })();
}
复制代码

上面的代码你可以理解为新增加的函数内部保存了每次循环变量i的值,那么当监听函数执行时将会获取闭包内保存的index变量的值,而不是之前的变量i的值。再看一下,效果OK了:


对地图API事件增强

熟悉google地图API的人可能知道,其事件相关的接口要比百度地图API的接口丰富,除了提供简单的addListener和removeListener之外,还提供了clearListeners、clearInstanceListeners、trigger等方法。那么这些功能在百度地图API中如何实现呢?实际上百度地图API的内部也有事件机制并且与对外公开的事件共用一套机制,如果API提供了诸如clearListeners的方法必然会对API内部的逻辑造成影响,因此也就没有提供类似的接口。如果开发者很喜欢google地图API的事件机制模式并且非用不可怎么办呢,没问题,这里和大家分享一个我的开源项目,名字暂定为EventWrapper,它基于百度地图API,但提供了类似google地图事件机制的接口形式。开源项目地址:https://github.com/jiazheng/EventWrapper。src目录下的main.js就是全部代码了,这是开发版本,如果直接使用可以获取release目录下的eventwrapper.min.js。

我们通过几个例子来看一下它的使用方法,首先需要引用这个js脚本,这里就直接使用github提供的原始数据的地址:

<script src="https://raw.github.com/jiazheng/EventWrapper/master/release/eventwrapper.min.js" type="text/javascript"></script>

下面我们添加两个事件监听:

var clickListener = EventWrapper.addListener(map, 'click', function(e){
    alert(e.point.lng +', '+ e.point.lat);
});
var dragListener = EventWrapper.addListener(map, 'dragend', function(e){
    alert(e.point.lng +', '+ e.point.lat);
});

移除的方式如下:

EventWrapper.removeListener(dragListener);

我们将之前addListener方法返回的对象传递给removeListener即可,这和google的使用方式一致。此外我们还可以清除某个对象所有通过此方式绑定的事件:

EventWrapper.clearInstanceListeners(map);  // 清除map实例所有的事件监听函数

此外EventWrapper还提供了addDomListener、addDomListenerOnce、addListenerOnce、clearListeners和trigger方法,具体使用方法可参考开发版本脚本中的注释信息(开发脚本原始数据地址:https://raw.github.com/jiazheng/EventWrapper/master/src/main.js)。

目前此项目基本完成,但是还没有经过大规模的测试和验证,可能存在不完善的地方,也欢迎广大开发者发现问题并进行反馈。


补充一个很多人都在问的问题

很多人在使用API时发现我绑定了map和一个marker的click事件,发现点击marker的时候,不仅marker的click事件会被触发,map的click事件也会被触发。API会将事件向上传递,实际上点击任何覆盖物都会向上传递到map。那问题是怎么区分呢?map的click事件的事件参数e中包含一个名为overlay的属性,所以只需要在事件处理函数中判断overlay是否存在即可区分。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值