jQuery droppable - 在拖动过程中接收事件(不仅仅是在初始拖动时) [英] jQuery droppable - receiving events during drag over (not just on initial drag over)

查看:67
本文介绍了jQuery droppable - 在拖动过程中接收事件(不仅仅是在初始拖动时)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am using jQuery droppable (in conjunction with jQuery draggable) to allow the user to add rows to an HTML table by dragging items from a list and dropping them on the table.

这种方法很有效,但是目前的逻辑是,当用户在表行上拖放时,新行会在下面添加它们所依赖的行。

This works well, however at present the logic is that when the user drag-drops on a table row the new row gets added below the row they dropped on.

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

It would be better if the new row's add position was based on whether the user dropped in the upper or lower half of an existing row.

这很容易在 drop 事件中计算,但我需要在用户拖动时提供UI反馈(我会通过手段来做)两个CSS类 droppable-above droppable-below 例如)。

This is easy enough to calculate in the drop event, but I need to give UI feedback as the user drags (which I would do by means of two CSS classes droppable-above and droppable-below for example).

这似乎不可能,因为 over 事件只会触发一次;当用户最初拖动droppable元素时。

This doesn't seem to be possible, as the over event only fires once; when the user initially drags over the droppable element.

是否有可能获得 over 事件当用户在可放置元素上时鼠标移动?

Is it possible to get the over event to fire for every mouse move while the user is over a droppable element?

如果是这样,那么我就可以这样做:

If so, then I'd be able to do this:

$("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
        }
    }
});

CSS样式类似......

The CSS styles would be something like...

droppable-above { border-top: solid 3px Blue; }
droppable-below { border-bottom: solid 3px Blue; }


推荐答案

如你所说, over (与其对应的 out )仅在droppable上引发一次。另一方面,每次鼠标移动时都会引发 draggable 拖动事件,并且似乎适合该任务。但是,这个策略存在两个问题:

As you said, over (like its counterpart out) is only raised once on the droppable. On the other hand, the drag event of the draggable is raised every time the mouse moves, and seems appropriate for the task. There are, however, two problems with this strategy:


  • 拖动是否会被提升或者不是draggable实际上位于droppable上,

  • 即使在这种情况下,droppable也不会传递给事件处理程序。

  • drag is raised whether or not the draggable actually lies over a droppable,
  • even in that case, the droppable is not passed to the event handler.

解决这两个问题的一种方法是使用jQuery的 over 处理程序相关联。 //api.jquery.com/data /> data()工具,并在 out drop中取消关联处理程序:

One way to solve both problems is to associate the droppable and the draggable in the over handler, using jQuery's data() facility, and disassociate them in the out and drop handlers:

$("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.
        }
    }
});

既然draggable知道它正在躺着的droppable,我们可以用<$更新元素的外观c $ c>拖动事件处理程序:

Now that the draggable knows the droppable it's lying over, we can update the element's appearance in a drag event handler:

$(".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");
            }
        }
    }
});

下面的代码是一个简单的测试用例,演示了这个解决方案(它基本上填补了上述评论的空白并将共同模式重构为辅助函数)。可放置的设置比前一个示例复杂得多,主要是因为新创建的表行必须像兄弟姐妹那样可以放置。

The code that follows is a simple test case that demonstrates this solution (it basically fills the commented gaps above and refactors common patterns into helper functions). The droppable setup is a little more intricate than in the previous example, mainly because the newly created table rows have to be made droppable like their siblings.

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

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>

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;
}

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");
    }
});

这篇关于jQuery droppable - 在拖动过程中接收事件(不仅仅是在初始拖动时)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆