在放下不同的可拖动对象后还原可拖动对象

Revert draggable after a different draggable is dropped

我有一个 2x2 的可拖放区域网格 [[A,B][C,D]],网格下方是一个 1x4 的可拖动区域网格。我只希望某些可拖动对象彼此相邻。因此,例如,如果 B 中有一个可拖动对象,而我将另一个不同的可拖动对象拖动到 A 中,是否有办法使 B 中的可拖动对象还原?可拖动对象具有数据行和数据列,因此如果需要,我可以在 prev/next 列中获取可拖动对象。

$(".draggable").draggable({
            scroll: false,
            snap: ".snaptarget",
            snapMode: "inner",
            stack: ".draggable",
            revert: function (event, ui) {
                var $draggable = $(this);
                $draggable.data("uiDraggable").originalPosition = {
                    top: 0,
                    left: 0
                };

                return !event;
            }
});

$(".snaptarget").droppable({
            accept: ".draggable",
            drop: function (event, ui) {
                var $draggable = $(ui.draggable);
                var $droppable = $(this);

                // This droppable is taken, so don't allow other draggables
                $droppable.droppable('option', 'accept', ui.draggable);

                ui.draggable.position({
                    my: "center",
                    at: "center",
                    of: $droppable,
                    using: function (pos) {
                        $draggable.animate(pos, "fast", "linear");
                    }
                });

                // Disable prev or next droppable if the pagewidth == 1
                if ($droppable.data("col") == 1) {
                    $droppable.next().droppable("option", "disabled", true);
                    var nextDrag = $(".draggable[data-row='" + $droppable.data("row") + "'][data-col='2']");
                    if (nextDrag.length) {
                        // I need to revert nextDrag if there is one.
                        // I've tried this but it doesn't seem to work
                        nextDrag.data("uiDraggable").originalPosition = {
                           top: 0,
                           left: 0
                        }
                    }
                }
            },
            tolerance: "pointer"
        });

做了一些工作,我对偏移和定位一向不擅长。这是关键:

  function returnItem(item, target) {
    // Get Origin
    var oPos = item.data("uiDraggable").originalPosition;
    // Adjust Postion using animation
    item.position({
      my: "top left",
      at: "top left+" + oPos.left,
      of: target,
      using: function(pos) {
        item.animate(pos, "fast", "linear");
      }
    });
  }

这是一个基于 Draggable Snap to element grid example 的工作示例:

https://jsfiddle.net/Twisty/a4ucb6y3/6/

HTML

<div id="target">
  <div class="snaptarget ui-widget-header" data-col="1" data-row="1" style="top: 0; left: 0;">
  </div>
  <div class="snaptarget ui-widget-header" data-col="2" data-row="1" style="top: 0; left: 80px;">
  </div>
  <div class="snaptarget ui-widget-header" data-col="1" data-row="2" style="top: 80px; left: 0;">
  </div>
  <div class="snaptarget ui-widget-header" data-col="2" data-row="2" style="top: 80px; left: 80px;">
  </div>
</div>

<br style="clear:both">

<div id="source">
  <div id="drag-A" class="draggable ui-widget-content" style="left: 0;">
    <p>Drag A</p>
  </div>
  <div id="draggable2" class="draggable ui-widget-content" style="left: 80px;">
    <p>Drag B</p>
  </div>
  <div id="draggable3" class="draggable ui-widget-content" style="left: 160px;">
    <p>Drag C</p>
  </div>
  <div id="draggable4" class="draggable ui-widget-content" style="left: 240px;">
    <p>Drag D</p>
  </div>
</div>

CSS

.draggable {
  width: 80px;
  height: 80px;
  font-size: .9em;
  position: absolute;
  top: 0;
}

.draggable p {
  text-align: center;
  height: 1em;
  margin-top: 30px;
}

#source {
  width: 320px;
  height: 80px;
  position: relative;
}

#target {
  width: 160px;
  height: 160px;
  position: relative
}

.snaptarget {
  width: 80px;
  height: 80px;
  position: absolute;
}

jQuery

$(function() {
  function returnItem(item, target) {
    // Get Origin
    var oPos = item.data("uiDraggable").originalPosition;
    // Adjust Postion using animation
    di.position({
      my: "top left",
      at: "top left+" + oPos.left,
      of: target,
      using: function(pos) {
        item.animate(pos, "fast", "linear");
      }
    });
  }

  $(".draggable").draggable({
    scroll: false,
    snap: ".snaptarget",
    snapMode: "inner",
    stack: ".draggable",
    revert: "invalid",
    start: function(e, ui) {
      var off = $("#source").position();
      ui.helper.data("uiDraggable").originalPosition = {
        top: ui.position.top,
        left: ui.position.left
      };
    }
  });

  $(".snaptarget").droppable({
    accept: ".draggable",
    drop: function(event, ui) {
      var $draggable = $(ui.draggable);
      var $droppable = $(this);

      // This droppable is taken, so don't allow other draggables
      $droppable.droppable('option', 'accept', ui.draggable);

      // Disable prev or next droppable if the pagewidth == 1
      if ($droppable.data("col") == 1) {
        $droppable.next().droppable("option", "disabled", true);
        var nextDrag = $(".draggable[data-row='" + $droppable.data("row") + "'][data-col='2']");
        if (nextDrag.length) {
          // I need to revert nextDrag if there is one.
          returnItem(nextDrag, $("#source"));
        }
      }
    },
    tolerance: "pointer"
  });
});

在draggable中,当我们开始拖动时,我们想要记录原始位置(以防我们稍后需要恢复)。 revert 选项设置为 invalid 以防用户将其拖离其他奇怪的地方。

我们将拖拽项目的position添加到data,方便以后读取。

当物品掉落时,魔法就发生了。您已完成所有检查,如果不合身,只需 return 物品。如果 nextDrag 存在,我们 return 它的来源。

展望未来,您可能需要考虑追加、克隆和删除 start/stop 事件中的元素。就像现在一样,我们实际上只是在调整元素的位置,而不是它们在 DOM 中的层次结构。根据您的需求,这可能无关紧要。