seven's blog | 百度地图自定义覆盖物手机端添加点击事件无效

百度地图自定义覆盖物手机端添加点击事件无效
2018年05月17日

最近在做百度地图添加自定义覆盖物时,遇到一个问题。起先参照api都很顺利,但是当我在给自定义的覆盖物添加点击事件时,问题来了:无法触发。

去网上找了一些解决方案,包括注册点击事件之类的,都没有解决。

之后无意发现,当把调试模式切出手机模式时,点击事件就能够正确的触发,由此得出结论,问题点在于页面是在手机端运行,所以尝试写入了手机端的常见事件,如touch,touchstart…,依旧无法解决,查了下发现是由于百度地图手机端默认的事件是拖动事件,屏蔽其他事件。

说一下最终解决方案吧,参考了这篇文章

引入js:http://api.map.baidu.com/library/EventWrapper/1.2/src/EventWrapper.js

使用:

BMapLib.EventWrapper.addDomListener(mySquare._div, "touchend", function(e){
    //...点击操作
});

tip:BMapLib是这个库的命名空间,BMap所有library都在bMapLib命名空间之下

下面贴出我的代码:

//html
<div class="bdMap_wrap" id="bdMap_pic"></div>//地图容器
//封装的js:customizeOverlay.js
/* 
 * 定义自定义覆盖物的构造函数
 * 参数:(你可以对应设置你自己需要传的参数)
 * point:坐标点
 * text:提示文字
 * num:坐标点上的数字标号
 */
function customizeOverlay(point,text,num){
    this._point=point;
    this._text=text;
    this._num=num;
};
// 继承API的BMap.Overlay 
customizeOverlay.prototype = new BMap.Overlay();
// 实现初始化方法  
customizeOverlay.prototype.initialize = function (map) {    
    // 保存map对象实例   
    this._map = map;        
    // 创建div元素,作为自定义覆盖物的容器   
    let div = document.createElement("div");    
    $(div).addClass('map_point_icon');//提前写好自定义覆盖的样式,然后这边用js创建dom
    div.innerHTML=this._num;
    let label = document.createElement("div");
    $(label).addClass('label_box');
    label.innerHTML=this._text;
    div.appendChild(label);
    // 将div添加到覆盖物容器中   
    map.getPanes().markerPane.appendChild(div);
    // 保存div实例   
    this._div = div;
    this._cwidth=this._div.clientWidth;
    this._cheight=this._div.clientHeight;
    // 需要将div元素作为方法的返回值,当调用该覆盖物的show、   
    // hide方法,或者对覆盖物进行移除时,API都将操作此元素。   
    return div;
}
// 实现绘制方法   
customizeOverlay.prototype.draw = function () {    
    // 根据地理坐标转换为像素坐标,并设置给容器    
    let position = this._map.pointToOverlayPixel(this._point);      
    this._div.style.left = position.x - this._cwidth/2 + "px";    
    this._div.style.top = position.y - this._cheight + "px";    
}
//页面调用,html文件底部

//引入需要的js
//...
<script type="text/javascript" src="http://api.map.baidu.com/library/EventWrapper/1.2/src/EventWrapper.js"></script>
<script type="text/javascript" src="customizeOverlay.js"></script>
//...

let map = new BMap.Map("bdMap_pic");//创建实例
let point = new BMap.Point(121.486705,31.245197); // 创建点坐标   
map.centerAndZoom(point, 11);// 初始化地图,设置中心点坐标和地图级别
map.setMapStyle({style:'light'});//设置地图主题
map.enableScrollWheelZoom(true);//开启鼠标滚轮缩放
map.setMinZoom(9);
map.setMaxZoom(18);
let pointData=[//用来测试的point,实际开发会从后台读取
    {
        name:'豫园',
        value1:121.498981,
        value2:31.232772
    },
    {
        name:'静安寺',
        value1:121.451697,
        value2:31.229792
    },
    {
        name:'上海大宁剧院',
        value1:121.463457,
        value2:31.290447
    }
];
//遍历pointData数组,添加多个自定义覆盖物
pointData.forEach((item,index)=>{
    let mySquare=new customizeOverlay(new BMap.Point(item.value1,item.value2), item.name, index+1);
    map.addOverlay(mySquare);
    BMapLib.EventWrapper.addDomListener(mySquare._div, "touchend", function(e){
        //事件处理
    });
});

以上。

需要再说明一点的是另一个问题:除了点击事件之外,我发现每次放大缩小地图的时候,覆盖都会先偏移一下才能回到正确的位置。

在封装draw事件时,因为是移动端,所以为了让我自定义的图片的底部中间位置对准point,无法通过确切的px值来计算,所以我使用了自定义图片的clientWidth和clientHeight。 但由于每次放大缩小地图时都会触发draw事件,而重新绘制开始clientWidth和clientHeight会变成0,所以位置会出现偏差。

解决方法就是上面代码写的那样,在初始化方法里面定义clientWidth和clientHeight,然后在draw函数里面引用,这样就可以保证不用每次draw时都需要重新监听覆盖物的宽高。

17 May 2018