已知:项目组里的产品采用 Electron + Vue 的前端技术栈。
最近发现一个奇怪的现象:在新功能页面中,当按下鼠标移动三维模型,若按住不放,把光标拖至 canvas 外释放鼠标,再将鼠标移回 canvas 内,此时即使不再次按下鼠标,也能移动模型,仿佛鼠标被粘连住一样。但在旧功能页面表现正常。
这部分 CesiumJS 代码是几乎沿用旧功能的,那怎么会出现不同表现形式呢?于是开展定位排查。、
思路一:是不是被其他业务逻辑影响了?
这点是首先想到的可能原因。但删除几乎所有其他代码后,问题仍存在。猜想错误。
思路二:阅读源码的鼠标相关操作逻辑,找出此时是什么逻辑缺了?
结果发现当鼠标移出目标元素 canvas 后,handlePointerUp() 不再被执行,也就是这时没有监听到 mouseup 。我也写了简单的 demo 进行验证,这其实才是正常的。但是为什么旧功能这时能监听到 mouseup 呢?
1 | // cesium.js |
尝试网上搜索了很多资料,比如 electron + mouseup,cesium + mouseup 等等,也看到一些网友有相同的问题。但仍旧没替我回答:为什么旧功能表现正常?
https://blog.csdn.net/zheng12tian/article/details/83877391
https://blog.csdn.net/isea533/article/details/71703442
其实,官方 demo 也有一样的问题:
又花了一些时间排查。
原来,答案就在 handlePointDown() 里的这句event.target.setPointerCapture(event.pointerId)
。setPointerCapture 可以确保一个元素持续地接收到一个 pointer 事件,即使这个事件的触发点已经移出了这个元素。自己平时确实很少使用这个 API。
参考:https://developer.mozilla.org/zh-CN/docs/Web/API/Element/setPointerCapture
思路三:那为什么新功能页面也加了这句,就不生效呢?
经过测试,与 iFrame 相关。这说的通,因为官方 demo 里的 cesium 也是 iFrame 的形式嵌入。
新功能是以 iFrame 的形式嵌入的。当子工程与父工程都不是简单的静态资源 html 页面形式,而是需要部署(涉及 webpack 打包等)时,setPointerCapture 在 chrome 不生效。
没错,经实践发现,在 firefox 里,自己写的页面与官方 demo 都没有这个问题,mouseup 能被监听到,是正常的……
结论:该问题与浏览器的内部实现有一定关系。