jQuery UI – 可拖动的 'snap' 事件 [英] jQuery UI – draggable 'snap' event

查看:22
本文介绍了jQuery UI – 可拖动的 'snap' 事件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm looking a way to binding the snap event.

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

When I'm dragging an element over my surface and the draggable element is snapped to a declared snap position I want to trigger an event.

像这样:

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

加分点:参考 .grid 元素,其中 draggable 元素被对齐.

Bonus point: with a reference to the .grid element where the draggable element was snapped.

推荐答案

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

The draggable widget does not expose such an event out of the box (yet). You could modify it and maintain your custom version or, better, derive a new widget from it and implement the new event there. There is, however, a third way.

这个问题,我们知道小部件在其中存储了一个潜在可捕捉"元素的数组snapElements 属性.反过来,此数组中的每个元素都会公开一个 snapping 属性,如果可拖动助手当前已捕捉到此元素,则该属性为 true,否则为 false(助手可以同时捕捉到多个元素).

From this question, we know the widget stores an array of the potentially "snappable" elements in its snapElements property. In turn, each element in this array exposes a snapping property that is true if the draggable helper is currently snapped to this element and false otherwise (the helper can snap to several elements at the same time).

snapElements 数组会针对每个 drag 事件更新,因此它在 drag 处理程序中始终是最新的.从那里,我们只需要从具有 data(),并调用它的 _trigger() 方法来引发我们自己的 snapped 事件(实际上是 dragsnapped 在引擎盖下).顺便说一下,我们可以$.extend() ui 对象使用 jQuery 对象包裹捕捉的元素:

The snapElements array is updated for every drag event, so it is always up-to-date in drag handlers. From there, we only have to obtain the draggable widget instance from the associated element with data(), and call its _trigger() method to raise our own snapped event (actually dragsnapped under the hood). In passing, we can $.extend() the ui object with a jQuery object wrapping the snapped element:

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

但是,上面的代码仍然可以改进.就目前而言,只要可拖动助手保持对齐,每个 drag 事件(发生很多)都会触发 snapped 事件一个元素.另外,snapping结束时不会触发任何事件,这不太实用,而且有损此类事件成对发生的约定(snapped-insnapped-out>).

The code above, however, can still be improved. As it stands, a snapped event will be triggered for every drag event (which occurs a lot) as long as the draggable helper remains snapped to an element. In addition, no event is triggered when snapping ends, which is not very practical, and detracts from the convention for such events to occur in pairs (snapped-in, snapped-out).

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

Luckily, the snapElements array is persistent, so we can use it to store state. We can add a snappingKnown property to each array element in order to track that we already have triggered a snapped event for that element. Moreover, we can use it to detect that an element has been snapped out since the last call and react accordingly.

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

Note that rather than introducing another snapped-out event, the code below chooses to pass an additional snapping property (reflecting the element's current state) in the ui object (which is, of course, only a matter of preference):

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

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

You can test this solution here.

最后,另一个改进可能是使 snapped 事件 cancelable,就像 drag 事件一样.为了实现这一点,如果对 _trigger() 的调用之一返回 false<,我们必须从 drag 处理程序返回 false/代码>.不过,在实施此操作之前,您可能需要三思,因为在一般情况下,取消对管理单元或管理单元的拖动操作看起来不像是一个非常用户友好的功能.

In closing, another improvement might be to make the snapped event cancelable, as the drag event is. To achieve that, we would have to return false from our drag handler if one of the calls to _trigger() returns false. You may want to think twice before implementing this, though, as canceling a drag operation on snap-in or snap-out does not look like a very user-friendly feature in the general case.

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

Update: From jQuery UI 1.9 onwards, the data() key becomes the widget's fully qualified name, with dots replaced by dashes. Accordingly, the code used above to obtain the widget instance becomes:

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

代替:

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

1.9 中仍支持使用非限定名称,但已弃用,1.10 中将不再支持.

Using the unqualified name is still supported in 1.9 but is deprecated, and support will be dropped in 1.10.

这篇关于jQuery UI – 可拖动的 'snap' 事件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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