概述
在总结方法之前,先总结一下问题。
用过leaflet的人都知道,leaflet中有这样一个方法:
L.geoJSON(data, { style: function (feature) { return {color: feature.properties.color}; } }).bindPopup(function (layer) { return layer.feature.properties.description; }).addTo(map);
这个方法可以将封装好的GeoJson直接转化为FeatureGroup,非常方便。
GeoJson 的 featureType 有多种,这里拿 Point 和 Polygon 两类来举例说明,它们在 leaflet 中是两个代表。Point 类型的 geojson 数据在转化为地图图层的渲染方式是 marker,本质上是 div,也就是说,如果你的 geojson 里有 1 万条数据,那它就会在地图上创建 1 万个 div,很恐怖有木有,事实上也是不可取,因为一口气创建一万个 div 还是带来了很大的工作量,一般配置的电脑上运行这样的页面会卡出翔;再说 Polygon 多边形类型,Polygon 类型的 geojson 数据在转化为地图图层的渲染方式是 Canvas,这与 marker 有本质上的区别,即使你的 geojson 里有 1 万条数据,它也只会在其所在的 Pane 上创建 1 个 Canvas标签,页面地图流畅程度丝毫不受影响。
说到这里,其实离本文的问题已经跑远了,但说这些也是为了更好的理解这个问题或者说现象。div 是有层级关系(zIndex)的,而且这种关系是非常容易被控制的,任何时候我们都可以很轻易去改变,那么 Canvas 呢?
在 leaflet 的使用中可能会碰到这样的情况,在同一层的 Pane 上,比如在 “ overlayPane ” 上,同时定义了以三角形为主和以四边形为主的 Polygon 类型的 FeatureGroup,因此最后渲染出的页面应该是这两个 Feature Group 的内容展示在同一个 Canvas 标签中,假如它们分别都绑定了各自的popup事件,而恰好它们在地图上的区域有所交叉和重叠(假设三角形在四边形的上方,即三角形覆盖了四边形的重叠区域),那这下子就尴尬了,当点击地图上它们的重叠区域时,这个问题的高潮也就来了。
从理论上无非四种结果:触发三角形的popup;触发四边形的popup;二者都没触发;二者都触发了。
而从测试后的事实的表象来看,无论是哪儿的重叠区域,被触发的,永远是下方被覆盖的四边形。
一开始我是懵比的,我觉得这是一个诡异的bug,一个问题的发生找不到合乎逻辑的解释。寥寥数行代码我反复看的心疲力乏,有一句话最能描述我当时的心境,理智让我怀疑一切!
好了,不兜圈子了,这个bug神秘的面纱下,其实就是事件穿透,事实的本质是最后一种预想,二者都触发了。leaflet 中 popup 有个特性,整个地图中有且只能有一个 popup 会被触发,事情的真相是,当鼠标点击它们的重叠区域时,首先会触发位于上方的三角形,紧接着触发下方的四边形。触发四边形的过程中会解除掉三角形的触发状态。这就是真相,一个典型的事件穿透问题。
搞清楚了问题的来龙去脉,解决问题的思路就一下打开了,可能稍微棘手点的就是,popup事件都是绑定在同一个canvas中的每一个单元上。
直接上代码,后面不想再多说了,还是要留下一些思考的空间。
var level_active = false; var ship_active = false;
/*=============================================== (实时)通航等级 ====================================================*/ function getPassLevelLayer() { if (grade_cache == "") { return; } levelLayer = L.geoJson(grade_cache, { style: function (feature) { return {color: feature.properties.color, weight: weightValueArray[map.getZoom()], pane: 'overlayPane'}; }, onEachFeature: function (feature, layer) { layer.bindPopup(eachFeaturePopup(feature)); layer.on("mouseover",function(){ level_active = true; }).on("mouseout",function () { level_active = false; }).on('click',function () { if(level_active&&ship_active){ ship_popup_obj.openPopup(); } }); } }); return levelLayer; }
/*===================================================== 船 舶 ========================================================*/ function loadShipSoapLayer() { if (shipSoapLayer == null) { shipSoapLayer = L.geoJson(ship_soap_cache, { style: function (feature) { return { fillColor: feature.properties.Color, fillOpacity: 1, color: "black", weight: 1, pane: 'overlayPane' }; }, onEachFeature: function (feature, layer) { layer.bindPopup(eachShipFeaturePopup(feature), { closeButton: false, className: "ShipSoap", Ship_Id: feature.properties.ShipId }).on('popupopen ', function (e) { if(level_active&&ship_active){ ship_popup_obj = e.target; } var shipid = map._popup.options.Ship_Id; $('.ShipSoap-Foot_Btn').on('click', function () { window.layer.open({ type: 2, skin: 'layui-layer-hei', title: '通航查询', shadeClose: false, shade: [0.9, '#6b6b6b'], maxmin: false, area: ['100%', '100%'], content: 'ship.html&shipId=' + shipid }); }) }).on('popupclose', function () { $('.ShipSoap-Foot_Btn').unbind(); }).on("mouseover",function(){ ship_active = true; }).on("mouseout",function () { ship_active = false; }); } }).setZIndex('9999'); } return shipSoapLayer; }
转载于:https://www.cnblogs.com/unique1319/p/7813858.html
最后
以上就是精明时光为你收集整理的leaflet中的事件穿透的全部内容,希望文章能够帮你解决leaflet中的事件穿透所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复