Drag and Drop API问题还是?

时间:2017-07-06 03:54:35

标签: javascript jquery html html5 draggable

我遇到了HTML5拖放API的问题。

长话短说,除了dragstartdragoverdrop之外,还有三个事件对我的目标至关重要。这三个事件是mousedownmouseupmouseleave

onmousedown事件

当用户在给定元素上触发mousedown事件时,以下函数会将属性和侦听器应用于自身和目标元素。

function doThis() {
  d.setAttribute('draggable', true)
  d.addEventListener('dragstart', dragStart)
  t.style.background = 'black'
  t.addEventListener('dragover', dragOver)
  t.addEventListener('drop', drop)
}

onmouseup&鼠标离开

当用户触发mouseupmouseleave事件时,将删除这些属性和侦听器。

function thenThis(){
  d.setAttribute('draggable', false)
  d.removeEventListener('dragstart', dragStart)
  t.style.background = 'none'
  t.removeEventListener('dragover', dragOver)
  t.removeEventListener('drop', drop)
}

我必须添加mouseleave侦听器,因为mouseup事件必须发生在绑定它的元素上才能触发它。在不应用mouseleave事件的情况下,用户可以触发mousedown事件,同时完全避免mouseup事件(由于浏览器本机检测到dblclick事件)双击元素,然后将光标从元素上滑下,同时不要放开鼠标按钮,直到它超出元素的周长。


问题......

如果用户单击可拖动元素太靠近其边缘,则尽管触发了mousedown事件,该元素仍会变为不可分割。

Here is an codepen MVC which can also be viewed below.

为什么会这样? mousedown偶数被触发,但元素仍然是无法分割的......

有人知道如何解决这个问题或者首先防止它发生吗?

var d = document.getElementById('draggable')
var t = document.getElementById('target')

d.addEventListener('mousedown', doThis)
d.addEventListener('mouseup', thenThis)
d.addEventListener('mouseleave', thenThis)
d.addEventListener('mouseleave', alertLeave)

function doThis(){
  d.setAttribute('draggable', true)
  d.addEventListener('dragstart', dragStart)
  t.style.background = 'black'
  t.addEventListener('dragover', dragOver)
  t.addEventListener('drop', drop)
}

function thenThis(){
  d.setAttribute('draggable', false)
  d.removeEventListener('dragstart', dragStart)
  t.style.background = 'none'
  t.removeEventListener('dragover', dragOver)
  t.removeEventListener('drop', drop)
}

function dragStart(e){
  e.dataTransfer.setData('text/plain', e.target.id);
  e.dataTransfer.effectAllowed = 'move';
}

function dragOver(e){
  e.preventDefault();
}

function drop(e){
  var data = e.dataTransfer.getData('text/plain');
  e.preventDefault();
  e.target.parentElement.appendChild(document.getElementById(data));
}

function alertLeave(){
  //alert('mouseleave')
}
body {
  display: flex;
  justify-content: space-around;
}

div {
  width: 50px;
  height: 50px;
}

#draggable {
  background: purple;
}

#target {
  border: solid 3px black;
}
<div id="draggable"></div>
<div id="target"></div>

1 个答案:

答案 0 :(得分:1)

当你尝试抓住靠近右边缘的左边元素时,问题是dragstart只要你将鼠标向右移动就会被触发,var d = document.getElementById('draggable') var t = document.getElementById('target') d.addEventListener('mousedown', doThis) d.addEventListener('mouseleave', thenThis) function doThis(){ console.log('mousedown'); d.setAttribute('draggable', true); d.addEventListener('dragstart', dragStart); t.style.background = 'black'; t.addEventListener('dragover', dragOver); t.addEventListener('drop', drop); } function thenThis(){ console.log('mouseleave'); d.setAttribute('draggable', false); d.removeEventListener('dragstart', dragStart); t.style.background = 'none'; t.removeEventListener('dragover', dragOver); t.removeEventListener('drop', drop); } function dragStart(e){ console.log('dragstart'); e.dataTransfer.setData('text/plain', e.target.id); e.dataTransfer.effectAllowed = 'move'; } function dragOver(e){ e.preventDefault(); } function drop(e){ var data = e.dataTransfer.getData('text/plain'); e.preventDefault(); e.target.parentElement.appendChild(document.getElementById(data)); }有机会被触发。您可以在此代码段中看到事件:

body {
  display: flex;
  justify-content: space-around;
}

.square {
  width: 50px;
  height: 50px;
}

#draggable {
  background: purple;
}

#target {
  border: solid 3px black;
}
<div id="draggable" class="square"></div>
<div id="target" class="square"></div>
mouseleave

为了避免这种情况,您可以capture the mouse而不是处理dragend。拖动操作开始后,您可以释放鼠标捕获并依赖var d = document.getElementById('draggable') var t = document.getElementById('target') var releaseCapture = null; d.addEventListener('mousedown', mouseDown); d.addEventListener('dragend', resetDraggableElement); function mouseDown() { releaseCapture = captureMouse(resetDraggableElement); d.setAttribute('draggable', true); d.addEventListener('dragstart', dragStart); t.style.background = 'black'; t.addEventListener('dragover', dragOver); t.addEventListener('drop', drop); } function resetDraggableElement() { d.setAttribute('draggable', false); d.removeEventListener('dragstart', dragStart); t.style.background = 'none'; t.removeEventListener('dragover', dragOver); t.removeEventListener('drop', drop); } function dragStart(e) { if (releaseCapture) { releaseCapture(); releaseCapture = null; } e.dataTransfer.setData('text/plain', e.target.id); e.dataTransfer.effectAllowed = 'move'; } function dragOver(e) { e.preventDefault(); } function drop(e) { var data = e.dataTransfer.getData('text/plain'); e.preventDefault(); e.target.parentElement.appendChild(document.getElementById(data)); } function captureMouse(mouseUpHandler) { var releaseCapture = function() { document.removeEventListener("mouseup", lostCaptureHandler, false); } var lostCaptureHandler = function() { releaseCapture(); if (mouseUpHandler) { mouseUpHandler(); } }; document.addEventListener("mouseup", lostCaptureHandler, false); return releaseCapture; }事件。当用户释放鼠标时(如果未拖动元素)或拖动操作结束时,将重置draggable元素属性。

body {
  display: flex;
  justify-content: space-around;
}

.square {
  width: 50px;
  height: 50px;
}

#draggable {
  background: purple;
}

#target {
  border: solid 3px black;
}
<div id="draggable" class="square"></div>
<div id="target" class="square"></div>
ID  V1
1   A
1   C
1   B
2   B
2   A
2   A
3   B
3   C
3   C