关于Openlayers Overlay事件监听的一个坑

一、问题产生:

我使用Overlay创建标绘操作的小方块元素,如下代码和如图。

在这里插入图片描述

在这里插入图片描述
然后我监听小方块的mousedown事件。用原始的事件监听:

element.addEventListener('mousedown',process_mousedown);

然后监听map的pointermove事件

this.map.on('pointermove',process_pointmove)

内部逻辑不用管。pc端测试,process_mousedownprocess_pointmove两个函数都能触发。逻辑可以正常写。

ok。换移动端。当然mousedown要添加额外的事件。

element.addEventListener('mousedown touchstart',process_mousedown);

测试,发现process_mousedown函数可以正常触发。但是process_pointmove这个函数却怎么也触发不了。

二、问题分析

跟踪Openlayers的源码。找到ol.map内分发事件的handleMapBrowserEvent,发现了这样一段代码。

 handleMapBrowserEvent(mapBrowserEvent) {
      //--还有其他逻辑
      let target = mapBrowserEvent.originalEvent.target;
      while (target instanceof HTMLElement) {
        if (target.parentElement === this.overlayContainerStopEvent_) {
          return;
        }
        target = target.parentElement;
      }
     //--事件往上层分发
    }

我们都知道。当OverLay 不设置stopEvent属性时,默认该属性为true。即所有overlay都放在ol-overlaycontainer-stopevent这个div内
在这里插入图片描述
图上红色的就是我的那两个控制点的元素。
也就是这个代码逻辑就是,当我事件触发到map层的时候,我判断这个事件的源头元素,如果这个源头元素是我这个ol-overlaycontainer-stopeventdiv下面的,则屏蔽所有的事件。你不管在map层用on监听什么事件,只要这个事件触发的源头是这个div下面的。你都监听不到。

为什么pc端可以?因为pc端的pointermove 源头元素都不是我的那个控制点DIV。但是对于移动端,因为我是按住这个控制点DIV进行拖动,所以源头元素就是我的这个控制点DIV,所以被屏蔽了。

我觉得这是Openlayer这块逻辑有问题,想屏蔽,pc的确没有屏蔽。不想屏蔽,移动端的却屏蔽了。

三、问题解决。

通过设置overlay的属性stopEvent为false,可以暂时解决这个问题。因为我的控制点被放到map内部的ol-overlaycontainer容器中去了。pointermove事件的源头也找不到我的控制点。所以没有被屏蔽掉。
在这里插入图片描述
大家看到这里应该可以了。但是我的问题还没有解决。这样干之后,我通过原生的dom监听的mousedowntouchstart事件居然不触发了。先记录到这里,我还得继续解决…

四、最终解决

问题解决了。我不能通过设置stopEvent为false解决问题。因为一旦设置了这个,我移动端pc端不管怎么监听都无法拿到我要点击的那个控制div。因为ol-overlaycontainer-stopevent永远盖在ol-overlaycontainer之上。事件都是从ol-overlaycontainer-stopevent传递出去的。

于是我只能想办法不通过map的那个有问题的函数handleMapBrowserEvent,并且能够监听pointmove事件。注意 openlayer官档没有提到map内部事件监听器MapBrowserEventHandler。其实这个是事件原始分发过来的地方。即我直接监听这个对象。查找源码,发现在map对象中果真有该对象:

在这里插入图片描述

该对象内部有个_listerer的map表记录了所有的注册的监听器:

在这里插入图片描述

发现其继承自ol.Event.Targetol.Event.Target继承自ol.Disposable自然找到了操作该监听器的方法:
在这里插入图片描述
于是解决方案:

map.mapBrowserEventHandler_.addEventListener('pointermove', xxx);

map.mapBrowserEventHandler_.removeEventListener('pointermove', xxx);

最终测试。完美解决。

五、另外说一个坑

注意,上面的removeEventListener的第二个参数(即绑定的函数)一定要存在,并且这个函数移除之后一定不能再次传递进来。
不信大家看源码~~~这不得不吐槽了。

在这里插入图片描述

当listener传递空值的时候。openlayer会检测是否在列表中存在。即使不存在,也是直接执行splice(-1,1)啊。理所当然的,系统监听的函数就会被移除,导致map对应的监听器被干掉。。。。。。慎用啊。

2022.6.3日(长期有效):打个广告,苏州华为终端BG面向社会招聘人才,Java /C C++ / Python / Javascript 。有兴趣来苏州的同学们 可以加我V 15850277051 ,走内推流程,有问必答!

  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 6
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值