最近在项目中使用百度地图的自定义覆盖物时发现在手机浏览器下click无法触发,虽然有touchstart,touchmove,touchend等方法,但都不适合项目逻辑。
下面的代码我简单地定义了一个红色矩形div,给它一个click事件,添加到地图中
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
body, html
{
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
font-family: "微软雅黑";
}
#allmap
{
margin: 0 0 3px;
height: 100%;
}
.customOverlay
{
background:#ff0000;
width:100px;height:100px;
position:absolute;
}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=d48dRYg4j4K81puarHtLXBheW40bG1HW"></script>
<title>2种地图</title>
</head>
<body>
<div id="allmap">
</div>
</body>
</html>
<script type="text/javascript">
/*
* 自定义标注
*/
var CustomOverlay = function (point, options) {
this._point = point;
this.opts = options;
}
// 通过JavaScript的prototype属性继承于BMap.Overlay
CustomOverlay.prototype = new BMap.Overlay();
CustomOverlay.prototype.initialize = function (map) {
this._map = map;
var div = this._div = document.createElement("div");
div.className = "customOverlay";
div.style.zIndex = BMap.Overlay.getZIndex(this._point.lat);
div.style.background = "#ff0000";
div.addEventListener("click", function () {
alert(111);
});
map.getPanes().markerPane.appendChild(div);
return div;
}
CustomOverlay.prototype.draw = function () {
var map = this._map;
var pixel = map.pointToOverlayPixel(this._point);
this._div.style.left = pixel.x + "px";
this._div.style.top = pixel.y + "px";
}
//百度地图API功能
//加载第一张地图
var map = new BMap.Map("allmap", { mapType: BMAP_NORMAL_MAP }); // 创建Map实例
var point = new BMap.Point(116.404, 39.915);
map.centerAndZoom(point, 11);
map.enableScrollWheelZoom(); //启用滚轮放大缩小
var point1 = new BMap.Point(116.414, 39.915);
var c1 = new CustomOverlay(point1);
map.addOverlay(c1);
// var marker = new BMap.Marker(point);
// map.addOverlay(marker);
// marker.addEventListener("click", function () {
// alert("我是marker,我能触发click事件");
// });
</script>
发现问题
用google浏览器的的手机模式进行调试,不会的请按f12
发现在手机模式下click事件并不会触发。
分析问题
我们禁用地图的拖拽功能
map.disableDragging();
发现click事件可以触发了,为什么禁用了地图的拖拽功能就能触发click事件了呢?
我们可以大胆猜测,是地图的click事件阻止了覆盖物click事件的执行。
现在我们可以去验证一下,按f12找到覆盖物的元素节点(浏览器调试就不多说了,大家应该都知道)
既然事件被父元素阻止了,那么按理来说只要把元素添加到其他容器事件应该就能正常被触发了,我们可以来试试
我把元素拖动到如图所示的位置,发现果然可以正常地触发事件了,这表明我的猜测应该是正确的。
知道了问题之后就是要解决问题
我不知道大家有没有注意到我上面代码中注释掉的5行代码,这5行代码的作用的添加一个marker,并赋予click事件.
说到marker,他和覆盖物都是通过同一个函数map.addOverlay添加到地图中,在网页中添加的位置也相同,可是为什么marker的
click事件可以被触发,而overlay的click事件就不能被触发呢?
下面我们来看看marker与 overlay有什么不同
把代码添加到项目中,刷新网页找到marker的节点
我们发现marker有2个节点,我们首先找到的是上面那个节点,删除这个节点我们会发现marker还是在地图上,但是click事件却
不能被触发
删除下面那个节点,marker在地图上消失了,不过点击marker原来的位置,click还是会被触发
很明显百度地图在添加marker时把marker分为了2部分,一部分为网页上的显示,二部分是事件的触发。
解决问题
方法1
//给jquery添加touchClick方法
(function () {
var defaults = {
start: function (self, event) { },
move: function (self, event) { },
end: function (self, event) { }
}
$.fn.touchClick = function (opts) {
if (typeof opts == "function") {
opts = $.extend({}, defaults, { end: opts });
} else {
opts = $.extend({}, defaults, opts);
}
this.each(function () {
var obj = $(this);
obj.bind("touchstart", function (event) {
obj.data("move", false);
opts.start.call(this, event);
}).bind("touchmove", function (event) {
console.log(event.originalEvent.targetTouches.length);
obj.data("move", true);
opts.move.call(this, event);
}).bind("touchend", function (event) {
if (obj.data("move")) {
return;
} else {
opts.end.call(this, event);
}
obj.data("move", false);
});
});
};
})(jQuery);
$(c1._div).touchClick(function () {
alert("touchClick");
});
这个方法需要jquery框架,还有一个缺点是在小米等手机中灵敏度不是很高
基于以上方法的缺点,我重新找了一个取巧办法
c2._div.addEventListener("touchstart", function () {
map2.disableDragging(); //禁用地图拖拽功能
});
c2._div.addEventListener("click", function () {
alert("click");
});
c2._div.addEventListener("touchend", function () {
map2.enableDragging(); //启用地图拖拽功能
});
上面的代码乍一看可行,实际上是错误的,这个就要谈谈事件的执行顺序
map.addEventListener("touchmove", function () {
map.enableDragging();
});
这下就能正常执行click事件了
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no" />
<style type="text/css">
body, html
{
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
font-family: "微软雅黑";
}
#map1_container, #map2_container
{
width: 100%;
height: 50%;
float: left;
overflow: hidden;
margin: 0;
}
#allmap1
{
margin: 0 0 3px;
height: 100%;
}
#allmap2
{
margin: 3px 0 0;
height: 100%;
}
.customOverlay
{
background: #ff0000;
width: 100px;
height: 100px;
position: absolute;
cursor: pointer;
-webkit-tap-highlight-color: rgba(0,0,0,0);
}
</style>
<script type="text/javascript" src="http://api.map.baidu.com/api?v=2.0&ak=d48dRYg4j4K81puarHtLXBheW40bG1HW"></script>
<title>2种地图</title>
<script src="../../js/jquery.js" type="text/javascript"></script>
</head>
<body>
<div id="map1_container">
<div id="allmap1">
</div>
</div>
<div id="map2_container">
<div id="allmap2">
</div>
</div>
</body>
</html>
<script type="text/javascript">
//给jquery添加touchClick方法
(function () {
var defaults = {
start: function (self, event) { },
move: function (self, event) { },
end: function (self, event) { }
}
$.fn.touchClick = function (opts) {
if (typeof opts == "function") {
opts = $.extend({}, defaults, { end: opts });
} else {
opts = $.extend({}, defaults, opts);
}
this.each(function () {
var obj = $(this);
obj.bind("touchstart", function (event) {
obj.data("move", false);
opts.start.call(this, event);
}).bind("touchmove", function (event) {
console.log(event.originalEvent.targetTouches.length);
obj.data("move", true);
opts.move.call(this, event);
}).bind("touchend", function (event) {
if (obj.data("move")) {
return;
} else {
opts.end.call(this, event);
}
obj.data("move", false);
});
});
};
})(jQuery);
/*
* 自定义标注
*/
var CustomOverlay = function (point, options) {
this._point = point;
this.opts = options;
}
// 通过JavaScript的prototype属性继承于BMap.Overlay
CustomOverlay.prototype = new BMap.Overlay();
CustomOverlay.prototype.initialize = function (map) {
this._map = map;
var div = this._div = document.createElement("div");
div.className = "customOverlay";
div.style.zIndex = BMap.Overlay.getZIndex(this._point.lat);
div.style.background = "#ff0000";
map.getPanes().markerPane.appendChild(div);
return div;
}
CustomOverlay.prototype.draw = function () {
var map = this._map;
var pixel = map.pointToOverlayPixel(this._point);
this._div.style.left = pixel.x + "px";
this._div.style.top = pixel.y + "px";
}
//百度地图API功能
//加载第一张地图
var map1 = new BMap.Map("allmap1", { mapType: BMAP_NORMAL_MAP }); // 创建Map实例
var point1 = new BMap.Point(116.404, 39.915);
map1.centerAndZoom(point1, 11);
map1.enableScrollWheelZoom(); //启用滚轮放大缩小
var c1 = new CustomOverlay(point1);
map1.addOverlay(c1);
$(c1._div).touchClick(function () {
alert("touchClick");
});
var marker = new BMap.Marker(point1);
map1.addOverlay(marker);
marker.addEventListener("click", function () {
alert("我是marker,我能触发click事件");
});
//加载第二张地图
var map2 = new BMap.Map("allmap2", { mapType: BMAP_SATELLITE_MAP }); // 创建Map实例
var point2 = new BMap.Point(116.404, 39.915);
map2.centerAndZoom(point2, 11);
map2.enableScrollWheelZoom(); //启用滚轮放大缩小
map2.addEventListener("touchmove", function () {
map2.enableDragging();
});
var c2 = new CustomOverlay(point2);
map2.addOverlay(c2);
c2._div.addEventListener("touchstart", function () {
map2.disableDragging(); //禁用地图拖拽功能
});
c2._div.addEventListener("click", function () {
alert("click");
});
</script>