即使使用 preventDefault 也检测 onmouseup/onmousemove
Detect onmouseup/onmousemove even if preventDefault is used
我问了这个问题:PDF.JS overlay can not be made draggable。
我注意到 PDF.js 似乎阻止了 document.onmousemove
和 document.onmouseup
事件的触发。
我认为解决方案是使用元素的 onmousemove 和 onmouseup,但是这会带来问题。
例如,如果您将鼠标移动得太快,元素的 onmousemove
和 onmouseup
事件将停止触发。如果您尝试将其拖出边界,也会发生同样的事情,该元素的事件将停止触发。您可以在下面的代码片段中自己尝试。
// 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>
我的问题是无论如何都要检测 mousemove
和 mouseup
,即使 event.preventDefault()
已被解雇。
我最好的猜测是:
document.querySelectorAll('*').forEach(e => e.addEventListener('mousemove', elementDrag);
document.querySelectorAll('*').forEach(e => e.addEventListener('mouseup', closeDragElement);
但是,我担心这会影响性能,尤其是 mousemove
。
DOM 事件传播分为三个阶段:捕获阶段、目标阶段和冒泡阶段。粗略地说,事件首先向下移动到目标,到达目标然后向上移动。
EventTarget.addEventListener() 有一个可选参数 useCapture
(参见 docs):
useCapture
Optional
A boolean value indicating whether events of this type will be
dispatched to the registered listener
before being dispatched to any
EventTarget
beneath it in the DOM tree. Events that are bubbling
upward through the tree will not trigger a listener designated to use
capture. Event bubbling and capturing are two ways of propagating
events that occur in an element that is nested within another element,
when both elements have registered a handle for that event. The event
propagation mode determines the order in which elements receive the
event. See DOM Level 3 Events and JavaScript Event order for a
detailed explanation. If not specified, useCapture
defaults to false
.
话虽这么说,您可以尝试类似的方法来监听捕获阶段的事件,而不是冒泡阶段:
document.addEventListener('mousemove', elementDrag, true);
document.addEventListener('mouseup', closeDragElement, true);
我问了这个问题:PDF.JS overlay can not be made draggable。
我注意到 PDF.js 似乎阻止了 document.onmousemove
和 document.onmouseup
事件的触发。
我认为解决方案是使用元素的 onmousemove 和 onmouseup,但是这会带来问题。
例如,如果您将鼠标移动得太快,元素的 onmousemove
和 onmouseup
事件将停止触发。如果您尝试将其拖出边界,也会发生同样的事情,该元素的事件将停止触发。您可以在下面的代码片段中自己尝试。
// 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>
我的问题是无论如何都要检测 mousemove
和 mouseup
,即使 event.preventDefault()
已被解雇。
我最好的猜测是:
document.querySelectorAll('*').forEach(e => e.addEventListener('mousemove', elementDrag);
document.querySelectorAll('*').forEach(e => e.addEventListener('mouseup', closeDragElement);
但是,我担心这会影响性能,尤其是 mousemove
。
DOM 事件传播分为三个阶段:捕获阶段、目标阶段和冒泡阶段。粗略地说,事件首先向下移动到目标,到达目标然后向上移动。
EventTarget.addEventListener() 有一个可选参数 useCapture
(参见 docs):
useCapture
OptionalA boolean value indicating whether events of this type will be dispatched to the registered
listener
before being dispatched to anyEventTarget
beneath it in the DOM tree. Events that are bubbling upward through the tree will not trigger a listener designated to use capture. Event bubbling and capturing are two ways of propagating events that occur in an element that is nested within another element, when both elements have registered a handle for that event. The event propagation mode determines the order in which elements receive the event. See DOM Level 3 Events and JavaScript Event order for a detailed explanation. If not specified,useCapture
defaults tofalse
.
话虽这么说,您可以尝试类似的方法来监听捕获阶段的事件,而不是冒泡阶段:
document.addEventListener('mousemove', elementDrag, true);
document.addEventListener('mouseup', closeDragElement, true);