jquery 如何在mousedown元素之外捕获mouseup事件?(即,为了正确的拖放?)

f2uvfpb9  于 2023-11-17  发布在  jQuery
关注(0)|答案(4)|浏览(129)

如果在触发onmousedown的元素之外释放鼠标按钮,则不会触发Javascript onmouseup event
这会导致JQuery UI中的拖放错误:当鼠标按钮在JQuery draggable元素的容器外释放时,该元素不会停止拖动(因为该元素在到达其父边界时会停止移动)。重现步骤:

  • 转到http://jqueryui.com/draggable/
  • 向下拖动可拖动对象,直到鼠标离开周围的容器
  • 释放鼠标按钮(此时不按鼠标按钮)
  • 将鼠标移回容器
  • 而可拖动对象仍在被拖动。我希望在我释放鼠标键时拖动就会停止-- * 不管 * 它在哪里释放。

我在最新的Chrome和IE中看到了这种行为。
是否有任何变通办法?
我知道我们可以停止在mouseoutmouseleave上拖动容器,但我想继续拖动,即使我在父容器之外,就像在google maps中一样(无论在哪里释放鼠标,它总是停止拖动Map)。

m4pnthwp

m4pnthwp1#

你可以让你的mousedown元素“捕获”指针。然后它总是会接收mouseup事件。在React中,这可能看起来像这样:

const onPointerDownDiv1 = (event: React.PointerEvent) => {
  (event.target as HTMLDivElement).setPointerCapture(event.pointerId);
  // Do something ...
};

const onPointerUpDiv1 = (event: React.PointerEvent) => {
  (event.target as HTMLDivElement).releasePointerCapture(event.pointerId);
  // Do something ...
};

个字符
下面是一个使用“普通”html + JavaScript的实现:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <div
      id="div1"
      style="
        position: absolute;
        left: 50px;
        top: 50px;
        width: 20px;
        height: 20px;
        background-color: red;
      "
    ></div>
  </body>
  <script>
    let isDragging = false;
    let offsetX = 0;
    let offsetY = 0;
    let divElement = document.getElementById("div1");

    divElement.addEventListener("pointerdown", onPointerDown);
    divElement.addEventListener("pointermove", onPointerMove);
    divElement.addEventListener("pointerup", onPointerUp);

    function onPointerDown(event) {
      divElement.setPointerCapture(event.pointerId);
      offsetX = event.clientX - divElement.offsetLeft;
      offsetY = event.clientY - divElement.offsetTop;
      isDragging = true;
    }

    function onPointerMove(event) {
      if (isDragging) {
        divElement.style.left = (event.clientX - offsetX).toString() + "px";
        divElement.style.top = (event.clientY - offsetY).toString() + "px";
      }
    }

    function onPointerUp(event) {
      divElement.releasePointerCapture(event.pointerId);
      isDragging = false;
    }
  </script>
</html>

55ooxyrt

55ooxyrt2#

我发现这是最好的解决方案:将mouseup事件处理程序附加到document。然后它将总是取消,即使您在浏览器外释放鼠标按钮。当然,这不是一个漂亮的解决方案,但显然,这是使拖动正确工作的唯一方法。
尝试以下解决方案:

  • 你会看到“拖动结束”总是会发生,无论你在哪里释放光标。
  • 此外,为了防止在拖动时选择文本,我添加了unselectable class
let dragging = false;
const dragEl = document.querySelector('div');
const logEl = document.querySelector('pre');

dragEl.addEventListener('mousedown touchstart', (evt) => {
  dragging = true;
  dragEl.classList.add('unselectable');
  logEl.textContent += 'drag START\n';
});
document.addEventListener('mouseup touchend', (evt) => {
  if (dragging) {
    event.preventDefault();
    dragEl.classList.remove('unselectable');
    dragging = false;
    logEl.textContent += 'drag END\n';
  }
});
div {
  background: red;
}

.unselectable {
  -webkit-user-select: none; /* Safari */        
  -moz-user-select: none; /* Firefox */
  -ms-user-select: none; /* IE10+/Edge */
  user-select: none; /* Standard */
}
<div>drag me</div>
<hr>
LOG:
<p><pre></pre></p>

更新

现在,the setPointerCapture API提供了一个更干净的解决方案,如this answer中所解释的。

deyfvvtc

deyfvvtc3#

最好的处理方法是在mousemove事件处理程序中检查当前按钮状态。如果按钮不再按下,则停止拖动。
如果你把mouseup事件放在文档上,那么你只是把问题向上移动,如果你在文档外(甚至在浏览器窗口外)释放按钮,原来的问题仍然会显示出来。
例如jQuery

$div.on("mousedown", function (evt) {
        dragging = true;
  }).on("mouseup", function (evt) {
        dragging = false;
  }).on("mousemove", function (evt) {
        if (dragging && evt.button == 0) {
            //Catch case where button released outside of div
            dragging = false;
        }
        if (dragging) {
          //handle dragging here
        }
  });

字符串
你可以跳过mouseup事件处理程序,因为它会被mousemove捕获,但我认为它仍然存在,可读性更强。

cidc1ykv

cidc1ykv4#

如果你创建了一个“index.html”文件,里面有下面的代码(你可以完全复制粘贴),它将显示使用普通html + JavaScript的工作解决方案。

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
  </head>
  <body>
    <div
      id="div1"
      style="
        position: absolute;
        left: 50px;
        top: 50px;
        width: 20px;
        height: 20px;
        background-color: red;
      "
    ></div>
  </body>
  <script>
    let isDragging = false;
    let offsetX = 0;
    let offsetY = 0;
    let divElement = document.getElementById("div1");

    divElement.addEventListener("pointerdown", onPointerDown);
    divElement.addEventListener("pointermove", onPointerMove);
    divElement.addEventListener("pointerup", onPointerUp);

    function onPointerDown(event) {
      divElement.setPointerCapture(event.pointerId);
      offsetX = event.clientX - divElement.offsetLeft;
      offsetY = event.clientY - divElement.offsetTop;
      isDragging = true;
    }

    function onPointerMove(event) {
      if (isDragging) {
        let newPosLeft = event.clientX - offsetX;
        if (newPosLeft < 30) {
          newPosLeft = 30;
        }
        let newPosTop = event.clientY - offsetY;
        if (newPosTop < 30) {
          newPosTop = 30;
        }
        divElement.style.left = newPosLeft.toString() + "px";
        divElement.style.top = newPosTop.toString() + "px";
      }
    }

    function onPointerUp(event) {
      divElement.releasePointerCapture(event.pointerId);
      isDragging = false;
    }
  </script>
</html>

字符串

相关问题