如何在event.preventDefault()触发时仍检测mousemove与mouseup事件
解决方案
你遇到的document级mousemove、mouseup事件被阻塞的问题,本质是PDF.js在内部处理鼠标事件时阻止了事件冒泡,导致绑定在冒泡阶段的document事件无法收到回调。
你不需要给所有元素绑定事件,只要将document的事件监听改为捕获阶段触发即可解决问题,捕获阶段的事件传递优先级高于元素自身的冒泡阶段处理,哪怕PDF.js阻止了冒泡,你绑定的事件依然会正常执行。
修改后的核心代码如下:
// Modified from w3schools draggable tutorial function dragElement(elmnt, _bounds) { var pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; elmnt.onmousedown = dragMouseDown; let bounds = [..._bounds]; bounds[2] -= +elmnt.style.width.slice(0, -2); bounds[3] -= +elmnt.style.height.slice(0, -2); function dragMouseDown(e) { e = e || window.event; e.preventDefault(); pos3 = e.clientX; pos4 = e.clientY; // 第三个参数设为true,代表在捕获阶段监听事件 document.addEventListener('mouseup', closeDragElement, true); document.addEventListener('mousemove', elementDrag, true); } function elementDrag(e) { e = e || window.event; e.preventDefault(); pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; let yC = elmnt.offsetTop - pos2, xC = elmnt.offsetLeft - pos1; if (xC < bounds[0]) xC = bounds[0]; else if (xC > bounds[2]) xC = bounds[2]; if (yC < bounds[1]) yC = bounds[1]; else if (yC > bounds[3]) yC = bounds[3]; elmnt.style.top = yC + "px"; elmnt.style.left = xC + "px"; } function closeDragElement() { // 移除事件时也要指定捕获阶段,否则无法正确移除 document.removeEventListener('mouseup', closeDragElement, true); document.removeEventListener('mousemove', elementDrag, true); } } dragElement(toDrag, [0, 0, 200, 200]);
方案优势
- 仅在document上绑定2个事件,性能损耗几乎可以忽略,远优于给全量元素绑定事件的方案
- 事件绑定在顶层document,完全不会出现鼠标移动过快、超出元素边界就停止触发事件的问题
- 不受PDF.js内部
event.preventDefault()、事件冒泡阻止逻辑的影响,事件触发稳定性高
内容的提问来源于stack exchange,提问作者trinalbadger587
相关产品推荐
相关产品推荐

