jQuery droppable - 在拖动过程中接收事件(不仅仅是在初始拖动时)

Ric*_*ett 24 javascript jquery jquery-ui-draggable jquery-ui-droppable

我使用jQuery droppable(与jQuery draggable结合使用)允许用户通过从列表中拖动项目并将其放在表格上来向HTML表格添加行.

这很好用,但是目前的逻辑是,当用户在表行上拖放时,新行将被添加他们放置的行的下方.

如果新行的添加位置基于用户是否放入现有行的上半部分或下半部分,那会更好.

这是很容易在计算drop事件,但我需要给UI反馈用户拖动(我会用两个CSS类的方式做droppable-above,并droppable-below举例).

这似乎不可能,因为over事件只发射一次; 当用户最初拖过可投放元素时.

是否有可能得到over火,每鼠标移动,而用户是在投掷的元素事件?

如果是这样,那么我就能做到这一点:

$("tr.droppable").droppable({
    over: function(event, ui) {
        if (/* mouse is in top half of row */) {
            $(this).addClass("droppable-above").removeClass("droppable-below");
        }
        else {
            $(this).removeClass("droppable-above").addClass("droppable-below");
        }
    },

    out: function(event, ui) {
        $(this).removeClass("droppable-above").removeClass("droppable-below");
    },

    drop: function(event, ui) {
        $(this).removeClass("droppable-above").removeClass("droppable-below");
        if (/* mouse is in top half of row */) {
            // Add new row above the dropped row
        }
        else {
            // Add new row below the dropped row
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

CSS样式会像......

droppable-above { border-top: solid 3px Blue; }
droppable-below { border-bottom: solid 3px Blue; }
Run Code Online (Sandbox Code Playgroud)

Fré*_*idi 30

正如你所说,over(就像它的对应物一样out)只在droppable上提出一次.另一方面,每次鼠标移动时都会引发可拖动drag事件,并且似乎适合该任务.但是,这个策略存在两个问题:

  • drag 是否可拖动实际上位于一个可放置的,
  • 即使在这种情况下,droppable也不会传递给事件处理程序.

解决这两个问题的一种方法是over使用jQuery的data()工具将droppable和draggable关联在处理程序中,并在outdrop处理程序中取消关联:

$("tr.droppable").droppable({
    over: function(event, ui) {
        if (/* mouse is in top half of row */) {
            $(this).removeClass("droppable-below")
                   .addClass("droppable-above");
        }
        else {
            $(this).removeClass("droppable-above")
                   .addClass("droppable-below");
        }
        ui.draggable.data("current-droppable", $(this));  // Associate.
    },

    out: function(event, ui) {
        ui.draggable.removeData("current-droppable");     // Break association.
        $(this).removeClass("droppable-above droppable-below");
    },

    drop: function(event, ui) {
        ui.draggable.removeData("current-droppable");     // Break association.
        $(this).removeClass("droppable-above droppable-below");
        if (/* mouse is in top half of row */) {
            // Add new row above the dropped row.
        }
        else {
            // Add new row below the dropped row.
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

既然draggable知道它所处的droppable,我们可以在drag事件处理程序中更新元素的外观:

$(".draggable").draggable({
    drag: function(event, ui) {
        var $droppable = $(this).data("current-droppable");
        if ($droppable) {
            if (/* mouse is in top half of row */) {
                $droppable.removeClass("droppable-below")
                          .addClass("droppable-above");
            } else {
                $droppable.removeClass("droppable-above")
                          .addClass("droppable-below");
            }
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

下面的代码是一个简单的测试用例,它演示了这个解决方案(它基本上填补了上面的注释空白并将常见模式重构为辅助函数).可放置的设置比前一个示例更复杂,主要是因为新创建的表行必须像其兄弟一样可以放置.

你可以在这个小提琴中看到结果.

HTML:

<div class="draggable">New item 1</div>
<div class="draggable">New item 2</div>
<div class="draggable">New item 3</div>
<div class="draggable">New item 4</div>
<div class="draggable">New item 5</div>
<p>Drag the items above into the table below.</p>
<table>
    <tr class="droppable"><td>Item 1</td></tr>
    <tr class="droppable"><td>Item 2</td></tr>
    <tr class="droppable"><td>Item 3</td></tr>
    <tr class="droppable"><td>Item 4</td></tr>
    <tr class="droppable"><td>Item 5</td></tr>
</table>
Run Code Online (Sandbox Code Playgroud)

CSS:

p {
    line-height: 32px;
}

table {
    width: 100%;
}

.draggable {
    background-color: #d0ffff;
    border: 1px solid black;
    cursor: pointer;
    padding: 6px;
}

.droppable {
    background-color: #ffffd0;
    border: 1px solid black;
}

.droppable td {
    padding: 10px;
}

.droppable-above {
    border-top: 3px solid blue;
}

.droppable-below {
    border-bottom: 3px solid blue;
}
Run Code Online (Sandbox Code Playgroud)

使用Javascript:

$(document).ready(function() {
    $(".draggable").draggable({
        helper: "clone",
        drag: function(event, ui) {
            var $droppable = $(this).data("current-droppable");
            if ($droppable) {
                updateHighlight(ui, $droppable);
            }
        }
    });

    initDroppable($(".droppable"));

    function initDroppable($elements)
    {
        $elements.droppable({
            over: function(event, ui) {
                var $this = $(this);
                updateHighlight(ui, $this);
                ui.draggable.data("current-droppable", $this);
            },
            out: function(event, ui) {
                cleanupHighlight(ui, $(this));
            },
            drop: function(event, ui) {
                var $this = $(this);
                cleanupHighlight(ui, $this);
                var $new = $this.clone().children("td:first")
                                .html(ui.draggable.html()).end();
                if (isInUpperHalf(ui, $this)) {
                    $new.insertBefore(this);
                } else {
                    $new.insertAfter(this);
                }
                initDroppable($new);
            }
        });
    }

    function isInUpperHalf(ui, $droppable)
    {
        var $draggable = ui.draggable || ui.helper;
        return (ui.offset.top + $draggable.outerHeight() / 2
                <= $droppable.offset().top + $droppable.outerHeight() / 2);
    }

    function updateHighlight(ui, $droppable)
    {
        if (isInUpperHalf(ui, $droppable)) {
            $droppable.removeClass("droppable-below")
                      .addClass("droppable-above");
        } else {
            $droppable.removeClass("droppable-above")
                      .addClass("droppable-below");
        }
    }

    function cleanupHighlight(ui, $droppable)
    {
        ui.draggable.removeData("current-droppable");
        $droppable.removeClass("droppable-above droppable-below");
    }
});
Run Code Online (Sandbox Code Playgroud)