Javascript 拖放不适用于指针事件

Javascript drag and drop not working with pointer events

提问人:user22911026 提问时间:11/15/2023 更新时间:11/15/2023 访问量:22

问:

我是 javascript 和 Web 开发的新手,所以我确信这里缺少一个概念,希望有一种简单的方法来解决这个问题。我正在使用指针事件进行拖放,似乎在使用触摸时效果很好。但是当使用鼠标时,可拖动的 div 将具有不可预知的行为。如果您在拖动 div 时快速移动鼠标,光标将失去元素,并且 div 将陷入困境。同样奇怪的是,可能相关的是,pointermove 事件将在没有首先触发指针的情况下触发。

我认为某种类型的默认行为导致了这个问题,所以我添加了一个 pointercancel 事件(没有帮助)。我已经将 e.preventDefault() 添加到处理程序中,但这也没有帮助。

<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
    <script src="script.js" defer></script>
    <title>Document</title>
  </head>

  <body>
    <div>
      <div class="container" id="lineup">
        <div class=draggable id="player1" draggable="false">1</div>
        <div class=draggable id="player2" draggable="false">2</div>
        <div class=draggable id="player3" draggable="false">3</div>
      </div>
    </div>
  </body>

</html>
* {
box-sizing: border-box;
}

body {
    font-family: Arial, Helvetica, sans-serif;
    margin: 0;
}
#player{
    border: 2px solid white;
    border-radius: 6px;
    margin: 2px;

}
.dragging{
    border: 5px solid white;
    border-radius: 6px;
    margin: 2px;
    color:blue; 
   
}

.draggable.dragging {
    opacity: .5;
}

.draggable{
    height: 50px;
    width: 50px;
    border: 1px solid #000;
    border-radius: 10px;
    float: left;
    background: blueviolet;
    margin: 10px;
    touch-action: none;

}
const draggables = document.querySelectorAll('.draggable')

draggables.forEach(draggable => {

  draggable.addEventListener('pointerdown', e => {
    e.preventDefault()
    console.log(e)
    draggable.classList.add('dragging')
    draggable.setAttribute('draggable', true)
  })
  
  draggable.addEventListener('pointermove', e => {
    console.log(e)
    e.preventDefault()
    const player = document.getElementById(e.target.attributes.id.nodeValue)
    if (player == null) return
    if (player.classList.contains('dragging')) {
      positionPlayer(e, player)
    } else {
      return
    }
  })
  
  draggable.addEventListener('pointerup', e => {
    console.log(e)
    e.preventDefault()
    draggable.classList.remove('dragging')
    draggable.setAttribute('draggable', false)
  })
  draggable.addEventListener('pointercancel', e => {
    console.log(e)
    e.preventDefault()
  })
})

function positionPlayer(e, player) {
  e.preventDefault()
  player.style.position = 'absolute'
  player.style.left = `${e.pageX-player.clientWidth/2}px`
  player.style.top = `${e.pageY-player.clientWidth/2}px`
  console.log(e)

}

https://jsfiddle.net/MG_03035/fcjxb5Lp/

JavaScript 拖放 指针事件

评论


答:

1赞 Nick Friesen 11/15/2023 #1

我建议使用,以便您可以轻松地依靠光标位置来应用拖放功能的位置。position: absolute;

然后,我还建议使用 ,和事件侦听器来更好地捕获您希望使用的用户响应类型。mouseupmousedownmousemove

最后,我会在触发拖动功能之前对 div 进行带边距的布局,然后在选择后删除 div 上的边距。

let offsetX, offsetY;
let isDragging = false;
let currentDraggable = null;

document.addEventListener('mousedown', (e) => {
  if (e.target.classList.contains('draggable')) {
    isDragging = true;
    currentDraggable = e.target;
    offsetX = e.clientX - currentDraggable.getBoundingClientRect().left;
    offsetY = e.clientY - currentDraggable.getBoundingClientRect().top;
    currentDraggable.style.margin = 0;
    currentDraggable.classList.add('dragging');
    currentDraggable.style.cursor = 'grabbing';
  }
});

document.addEventListener('mousemove', (e) => {
  if (!isDragging) return;

  const x = e.clientX - offsetX;
  const y = e.clientY - offsetY;

  currentDraggable.style.left = `${x}px`;
  currentDraggable.style.top = `${y}px`;
});

document.addEventListener('mouseup', () => {
  if (isDragging) {
    isDragging = false;
    currentDraggable.classList.remove('dragging');
    currentDraggable.style.cursor = 'grab';
    currentDraggable = null;
  }
});
body {
  margin: 0;
  padding: 10px;
  overflow: hidden;
  font-family: Arial, Helvetica, sans-serif;
}

div:nth-child(2) {
  margin-left: 70px;
}

div:nth-child(3) {
  margin-left: 135px;
}

.draggable {
  width: 50px;
  height: 50px;
  border: 1px solid #000;
  border-radius: 10px;
  background-color: blueviolet;
  position: absolute;
  cursor: grab;
  margin: 5px;
}

.dragging {
  border: 5px solid white;
  margin: 2px;
  color: blue;
}

.draggable.dragging {
  opacity: .5;
}
<!DOCTYPE html>
<html lang="en">

  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="styles.css">
    <script src="script.js" defer></script>
    <title>Document</title>
  </head>

  <body>
    <div>
      <div class="container" id="lineup">
        <div class=draggable id="player1">1</div>
        <div class=draggable id="player2">2</div>
        <div class=draggable id="player3">3</div>
      </div>
    </div>
  </body>

</html>

0赞 user22911026 12/6/2023 #2

谢谢尼克。我看到您通过将侦听器放在文档上解决了鼠标问题。触摸侦听器不是以这种方式工作的。我不得不把它们放在 div 上才能让它们工作......有点。我一直在寻找一种使用这两种类型的侦听器的简单方法。为此,答案是jQuery。我刚刚开始 Web 开发,所以我不知道 jQuery 的存在。:)对于任何可能正在阅读本文的人,对于像我这样的 Web 开发来说,我建议您先学习 vanilla js,然后学习 jQuery。您将体会到jQuery的帮助和效率。