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

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

问题描述

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

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

类似这样的东西:

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

加分点:引用.grid元素,其中可拖动元素被捕捉.

解决方案

draggable小部件没有立即显示此类事件.您可以修改它并维护您的自定义版本,或者更好的是,从中派生一个新的小部件并在那里实现新的事件.但是,还有第三种方式.

此问题,我们知道该小部件在其snapElements中存储了一系列潜在的可扣紧"元素财产.反过来,如果当前可拖动的辅助对象已被捕捉到该元素,则此数组中的每个元素都显示一个true属性,该属性为true,否则显示为false(该辅助对象可以同时捕捉到多个元素).

对于每个drag事件,都会更新snapElements数组,因此在drag处理程序中,该数组始终是最新的.从那里,我们只需要使用 data()从关联的元素中获取draggable小部件实例. ,并调用其_trigger()方法引发我们自己的snapped事件(实际上是dragsnapped背后的事件).通过传递,我们可以 $ .extend() ui对象,并使用jQuery对象包装捕捉的元素:

$(".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事件.此外,捕捉结束时不会触发任何事件,这不太实际,并且有损于此类事件成对发生的惯例(snapped-insnapped-out).

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

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

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

您可以在此处进行测试.

最后,与drag事件一样,另一个改进可能是使snapped事件可取消.为此,如果对_trigger()的调用之一返回了false,则必须从drag处理程序中返回false.不过,您可能需要三思而后行,因为在通常情况下,取消对管理单元或管理单元的拖动操作看起来并不像一个非常用户友好的功能.

更新: :从jQuery UI 1.9起,

代替:

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

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

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

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.

Something like this:

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

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

解决方案

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.

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).

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

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).

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.

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.

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.

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

Instead of:

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

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

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

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