当我拖着时,dragend,dragenter和dragleave立即开火

时间:2013-01-07 20:44:58

标签: javascript jquery html5 drag-and-drop draggable

我正在尝试制作一个可以通过拖放重新定位的元素列表。第一个元素Box 1在100%的时间内都能正常工作。有时第二个框可以工作,但其他框都没有按预期工作。一旦你开始拖动它们,它们似乎会立即触发所有拖动事件。

如果重要的话,我正在使用最新的Chrome(第23版)。

var $questionItems = $('.question-item');

$questionItems
  .on('dragstart', startDrag)
  .on('dragend', removeDropSpaces)
  .on('dragenter', toggleDropStyles)
  .on('dragleave', toggleDropStyles);


function startDrag(){
  console.log('dragging...');
  addDropSpaces();
}

function toggleDropStyles(){
  $(this).toggleClass('drag-over');
  console.log(this);
}


function addDropSpaces(){
  $questionItems.after('<div class="empty-drop-target"></div>');
  console.log('drop spaces added');
}

function removeDropSpaces(){
  $('.empty-drop-target').remove();
  console.log('drop spaces removed');
}

这是HTML:

<div class="question-item" draggable="true">Box 1: Milk was a bad choice.</div>
<div class="question-item" draggable="true">Box 2: I'm Ron Burgundy?</div>
<div class="question-item" draggable="true">Box 3: You ate the entire wheel of cheese?</div>
<div class="question-item" draggable="true">Box 4: Scotch scotch scotch</div>

以下是我的代码的jsFiddle:http://jsfiddle.net/zGSpP/5/

6 个答案:

答案 0 :(得分:25)

刚出现这个问题 - 这是一个Chrome错误,你不能在dragStart事件中操纵DOM,否则dragEnd会立即触发。我的解决方案原来是 - 使用setTimeout()并在你超时的函数内操作DOM。

答案 1 :(得分:8)

答案 2 :(得分:6)

不确定它是否是一个bug,但我认为当你在dragstart处理程序中更改DOM时会出现问题。我认为第一个盒子工作的原因与它的位置在DOM中的其他盒子之前的事实有关,当你改变DOM时,第一个盒子的位置(?)不受影响,并且拖拉事件可靠地开火。

您需要稍微重构一下代码,并在dragenter事件处理程序中添加dropSpaces。您需要更改addDropSpaces方法以适应它将被多次调用的事实。

答案 3 :(得分:0)

jQuery的生活更轻松。这正是您所描述的,使用jQueryUI。

http://jqueryui.com/draggable/#sortable

允许排序。代码:

<!doctype html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <title>jQuery UI Draggable + Sortable</title>
    <link rel="stylesheet" href="http://code.jquery.com/ui/1.9.2/themes/base/jquery-ui.css" />
    <script src="http://code.jquery.com/jquery-1.8.3.js"></script>
    <script src="http://code.jquery.com/ui/1.9.2/jquery-ui.js"></script>
    <link rel="stylesheet" href="/resources/demos/style.css" />
    <style>
    ul { list-style-type: none; margin: 0; padding: 0; margin-bottom: 10px; }
    li { margin: 5px; padding: 5px; width: 150px; }
    </style>
    <script>
    $(function() {
        $( "#sortable" ).sortable({
            revert: true
        });
        $( "#draggable" ).draggable({
            connectToSortable: "#sortable",
            helper: "clone",
            revert: "invalid"
        });
        $( "ul, li" ).disableSelection();
    });
    </script>
</head>
<body> 
<ul>
    <li id="draggable" class="ui-state-highlight">Drag me down</li>
</ul>

<ul id="sortable">
    <li class="ui-state-default">Item 1</li>
    <li class="ui-state-default">Item 2</li>
    <li class="ui-state-default">Item 3</li>
    <li class="ui-state-default">Item 4</li>
    <li class="ui-state-default">Item 5</li>
</ul>

</body>
</html> 

另见:http://jqueryui.com/sortable/

尝试手动添加事件,很长一段时间,例如:

$questionItems[0].on('dragstart', startDrag); 
$questionItems[0].on('dragend', removeDropSpaces) 
$questionItems[0].on('dragenter', toggleDropStyles) 
$questionItems[0].on('dragleave', toggleDropStyles); 
$questionItems[1].on('dragstart', startDrag); 
$questionItems[1].on('dragend', removeDropSpaces) 
$questionItems[1].on('dragenter', toggleDropStyles)     
$questionItems[1].on('dragleave', toggleDropStyles); 

等。只是为了看到效果?

答案 4 :(得分:-1)

更改此功能

function addDropSpaces()
{
  $(this).after('<div class="empty-drop-target"></div>');
}

在您的版本中,您将在每个$ questionItems之后添加该div。

答案 5 :(得分:-1)

您需要阻止“事件”冒泡,以免引发其他事件。见https://developer.mozilla.org/en-US/docs/DOM/event.stopPropagation

对于startDrag,toggleDropStyles,removeDropSpaces函数,你会写这样的东西:

function startDrag(ev) {
   ev.stopPropagation();
   ... your code here ...
}