【问题标题】:jQuery UI – draggable 'snap' eventjQuery UI – 可拖动的“捕捉”事件
【发布时间】:2012-07-21 15:26:49
【问题描述】:

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

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

类似这样的:

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

加分项:参考.grid 元素,其中可拖动 元素被捕捉

【问题讨论】:

    标签: jquery-ui jquery-ui-draggable


    【解决方案1】:

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

    this question,我们知道小部件在其snapElements 属性中存储了一个潜在“可对齐”元素的数组。反过来,这个数组中的每个元素都会暴露一个 snapping 属性,如果可拖动助手当前与该元素对齐,则该属性为 true,否则为 false(助手可以同时对齐多个元素)。

    snapElements 数组会针对每个 drag 事件进行更新,因此它在 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;
            // ...
        }
    });
    

    你可以测试这个解决方案here

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

    更新: 从 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 中放弃支持。

    【讨论】:

    • 你会不会超级友善,并使用捕捉的 id 和捕捉到的元素更新你的捕捉 - 我使用 1.9.1 但需要找出捕捉与捕捉到 - 如果它在上方、下方、左侧或右侧,内容会有所不同 - 但现在我只找到了捕捉对象及其位置()
    • @mplungjan,如果我正确理解您的评论,那么该信息已经存在。 “捕捉”元素在ui.helper 中可用,当ui.snappingtrue 时,“捕捉到”元素为ui.snapElement
    • Here is the followup - 还没有接受者:(
    • 需要注意的是,"$(this).data("draggable")" 在较新的版本中已经被重命名为 $(this).data("ui-draggable")...
    • @Andrew,您是否完整阅读了我的回答,包括最后的更新?
    【解决方案2】:

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

    【讨论】:

    • 我知道我的回答有点长,但您是否尝试完整阅读? :)
    • 不同的是,$(this).data('draggable') 在 1.10+ 中不存在。您必须改用“ui-draggable”。而不是仅仅发布整套代码,他真的应该这么说。
    猜你喜欢
    • 2010-11-20
    • 2012-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多