检测鼠标向上/鼠标移动,即使使用了 preventDefault



我问了这个问题:PDF.JS叠加层不能被拖动。

我注意到 PDF.js 似乎阻止了document.onmousemovedocument.onmouseup事件被触发。

我认为解决方案是使用该元素的onmousemove和onmouseup,但这会带来问题。

例如,如果鼠标移动速度过快,元素的onmousemoveonmouseup事件将停止触发。同样的事情发生,如果你尝试把它拖出界外,元素的事件将停止触发。您可以在下面的代码片段中亲自尝试。

// Modified from https://www.w3schools.com/howto/howto_js_draggable.asp
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;
elmnt.onmouseup = closeDragElement; // Originally document.onmouseup
elmnt.onmousemove = elementDrag; // Originally document.onmousemove
}

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()
{
elmnt.onmouseup = null; // Originally document.onmouseup
elmnt.onmousemove = null; // Originally document.onmousemove
}
}
dragElement(toDrag, [0, 0, 200, 200]);
<div style="
position: absolute;
left:     0;
top:      0;
width:    200px;
height:   200px;
border:   1px solid black
" onmousedown="event.preventDefault()" onmouseup="event.preventDefault()">
<h1 style="text-align:center">My PDF</h1>
<div style="
position: absolute;
left:     150px;
top:      150px;
width:    25px;
height:   25px;
border:   1px solid black;
">
</div>
<div id=toDrag style="
cursor:   move;
position: absolute;
left:     10px;
top:      25px;
width:    25px;
height:   25px;
border:   1px solid black;
background-color: #cac;
border-radius:    25px
">
</div>
</div>

我的问题是,即使event.preventDefault()被解雇,也要检测mousemovemouseup

我最好的猜测是这样的:

document.querySelectorAll('*').forEach(e => e.addEventListener('mousemove', elementDrag);
document.querySelectorAll('*').forEach(e => e.addEventListener('mouseup', closeDragElement);

但是,我担心这可能会影响性能,尤其是在mousemove上。

DOM 事件传播分为三个阶段:捕获阶段、目标阶段和气泡阶段。粗略地说,事件首先向下工作到目标,到达目标,然后又向上工作。

EventTarget.addEventListener() 有一个可选参数useCapture(请参阅文档):

useCapture可选

一个布尔值,指示此类型的事件是否为 在被派送给任何listenerEventTarget在它下面的 DOM 树中。冒泡的事件 向上通过树不会触发指定使用的侦听器 捕获。事件冒泡和捕获是传播的两种方式 嵌套在另一个元素中的元素中发生的事件, 当两个元素都为该事件注册句柄时。活动 传播模式确定元素接收 事件。请参阅 DOM 级别 3 事件和 JavaScript 事件顺序 详细解释。如果未指定,useCapture默认为false

话虽如此,您可以尝试类似的东西来侦听捕获阶段的事件,而不是气泡阶段:

document.addEventListener('mousemove', elementDrag, true);
document.addEventListener('mouseup', closeDragElement, true);

最新更新