jQuery UI - 可拖动的'snap'事件

时间:2012-07-23 11:37:10

标签: jquery-ui jquery-ui-draggable

我正在寻找绑定snap事件的方法。

当我在表面上拖动一个元素并且 draggable 元素对齐时,我想要触发一个事件。

这样的事情:

$(".drag").draggable({
  snap: ".grid",
  snaped: function( event, ui ) {}
});

加分点:引用可拖动元素快照.grid元素。

2 个答案:

答案 0 :(得分:26)

draggable窗口小部件(尚未)公开此类事件。您可以修改它并维护自定义版本,或者更好地从中派生新的窗口小部件并在那里实现新事件。然而,还有第三种方式。

this question开始,我们知道小部件在其snapElements属性中存储了一个潜在“可抢占”元素的数组。反过来,如果可拖动帮助器当前被捕捉到此元素,则此数组中的每个元素都会公开snapping属性true,否则会显示false(帮助程序可以捕捉到同一时间)。

每个snapElements事件都会更新drag数组,因此drag处理程序中的draggable数组始终是最新的。从那里,我们只需要使用data()从关联元素中获取_trigger()窗口小部件实例,并调用其snapped方法来引发我们自己的dragsnapped事件(实际上{{ 1}}在引擎盖下)。顺便说一下,我们可以$.extend() ui对象用jQuery对象包装snapped元素:

$(".drag").draggable({
    drag: function(event, ui) {
        var draggable = $(this).data("draggable");
        $.each(draggable.snapElements, function(index, element) {
            if (element.snapping) {
                draggable._trigger("snapped", event, $.extend({}, ui, {
                    snapElement: $(element.item)
                }));
            }
        });
    },
    snap: ".grid",
    snapped: function(event, ui) {
        // Do something with 'ui.snapElement'...
    }
});

但是,上面的代码仍然可以改进。就目前而言,只要可拖动帮助程序保持对齐元素,就会为每个snapped事件(发生很多)触发drag事件。此外,捕捉结束时不会触发任何事件,这不是很实际,并且会导致这些事件成对发生(snapped-insnapped-out)。

幸运的是,snapElements数组是持久的,因此我们可以使用它来存储状态。我们可以为每个数组元素添加snappingKnown属性,以便跟踪我们已经触发了该元素的snapped事件。此外,我们可以使用它来检测自上次调用以来元素已被抢断并作出相应的反应。

请注意,下面的代码选择在snapped-out对象中传递额外的snapping属性(反映元素的当前状态),而不是引入另一个ui事件。当然,只是一个偏好的问题):

$(".drag").draggable({
    drag: function(event, ui) {
        var draggable = $(this).data("draggable");
        $.each(draggable.snapElements, function(index, element) {
            ui = $.extend({}, ui, {
                snapElement: $(element.item),
                snapping: element.snapping
            });
            if (element.snapping) {
                if (!element.snappingKnown) {
                    element.snappingKnown = true;
                    draggable._trigger("snapped", event, ui);
                }
            } else if (element.snappingKnown) {
                element.snappingKnown = false;
                draggable._trigger("snapped", event, ui);
            }
        });
    },
    snap: ".grid",
    snapped: function(event, ui) {
        // Do something with 'ui.snapElement' and 'ui.snapping'...
        var snapper  = ui.snapElement.attr("id"),snapperPos = ui.snapElement.position(),
            snappee  = ui.helper.attr("id"),     snappeePos = ui.helper.position(),
            snapping = ui.snapping;
        // ...
    }
});

您可以测试此解决方案here

最后,另一项改进可能是snapped事件可取消,因为drag事件是。为实现这一目标,如果对false的一次调用返回drag,我们必须从_trigger()处理程序返回false。但是,在实现此操作之前,您可能需要三思而后行,因为取消对管理单元或管理单元的拖动操作在一般情况下看起来不是一个非常用户友好的功能。

更新: 从jQuery UI 1.9开始,the data() key becomes the widget's fully qualified name, with dots replaced by dashes。因此,上面用于获取窗口小部件实例的代码变为:

var draggable = $(this).data("ui-draggable");

而不是:

var draggable = $(this).data("draggable");

1.9中仍然支持使用非限定名称但不推荐使用,支持将在1.10中删除。

答案 1 :(得分:1)

在jquery-ui 1.10.0中,上面的代码不起作用。相反,拖动功能是:

drag: function(event, ui) {
  var draggable = $(this).data("ui-draggable")
  $.each(draggable.snapElements, function(index, element) {
    if(element.snapping) {
      draggable._trigger("snapped", event, $.extend({}, ui, {
        snapElement: $(element.item)
      }));
    }
  });
}