12

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

当我在我的表面上拖动一个元素并且可拖动元素被捕捉到声明的捕捉位置时,我想触发一个事件。

像这样的东西:

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

加分项:引用.grid可拖动元素被捕捉的元素。

4

2 回答 2

27

draggable部件(目前)还没有公开这样的事件。您可以修改它并维护您的自定义版本,或者更好的是,从中派生一个新小部件并在那里实现新事件。然而,还有第三种方式。

这个问题snapElements中,我们知道小部件在其属性中存储了一个潜在“可对齐”元素的数组。反过来,该数组中的每个元素都会公开一个snapping属性,true即可拖动助手当前是否对齐到该元素,false否则(助手可以同时对齐多个元素)。

snapElements数组会针对每个事件进行更新,因此它在处理程序drag中始终是最新的。drag从那里,我们只需要使用data()draggable从关联元素中获取小部件实例,并调用它的方法来引发我们自己的事件(实际上是在幕后)。顺便说一句,我们可以$.extend()使用jQuery 对象包装捕捉到的元素:_trigger()snappeddragsnappedui

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

您可以在此处测试此解决方案。

最后,另一个改进可能是使snapped事件可取消,就像drag事件一样。为了实现这一点,如果对返回的调用之一,我们将不得不false从我们的处理程序返回。不过,在实现此功能之前,您可能需要三思而后行,因为在一般情况下,取消对 snap-in 或 snap-out 的拖动操作看起来并不是一个非常用户友好的功能。drag_trigger()false

更新:从 jQuery UI 1.9 开始,data()成为小部件的完全限定名称,点被替换为破折号。因此,上面用于获取小部件实例的代码变为:

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

代替:

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

1.9 中仍支持使用非限定名称,但已弃用,并且将在 1.10 中删除支持。

于 2012-07-24T13:25:05.943 回答
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)
      }));
    }
  });
}
于 2013-02-10T17:14:44.563 回答