jQuery UI-перетаскиваемое событие " snap

Я ищу способ связывания snap событие.

когда я перетаскиваю элемент по моей поверхности и разрешить элемент огрызнулась в объявленную позицию привязки я хочу вызвать событие.

что-то вроде этого:

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

бонусный балл: со ссылкой на .grid элемент, где разрешить элемент огрызнулась.

2 ответов


на draggable виджет не выставляет такое событие из коробки (пока). Вы можете изменить его и сохранить свою пользовательскую версию или, лучше, получить из него новый виджет и реализовать новое событие. Однако есть и третий способ.

С этот вопрос, мы знаем, что виджет хранит массив потенциально "привязываемых" элементов в своем snapElements собственность. В свою очередь, каждый элемент в этом массиве предоставляет snapping имущества true если перетаскивать helper в настоящее время привязан к этому элементу и false в противном случае (помощник может привязать к нескольким элементам одновременно).

на snapElements массив обновляется для каждого drag событие, поэтому оно всегда актуально в drag обработчики. Оттуда нам нужно только получить draggable экземпляр виджета из связанного элемента с data (), и назвать его _trigger() метод, чтобы поднять наш собственный snapped событие (на самом деле dragsnapped под капотом). Попутно мы можем $.extend () the 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'...
    }
});

код выше, однако, все еще может быть улучшен. В его нынешнем виде a snapped событие будет запускаться для каждого drag событие (что происходит большое) до тех пор, пока перетаскиваемый помощник остается привязанным к элементу. Кроме того, никакое событие не запускается при замыкании концов, что не очень практично и отвлекает от конвенции для таких событий парами (snapped-in, snapped-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 наших drag обработчик, если один из вызовов _trigger() возвращает false. Вы можете подумать дважды, прежде чем реализовать это, хотя, как отмена операции перетаскивания на оснастке или оснастки не выглядит как очень удобная функция в общем случае.

обновление: от jQuery UI 1.9 и далее,the data() ключ становится полным именем виджета, с точками, замененными тире. Соответственно, код, используемый выше для получения экземпляра виджета, становится:

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

вместо из:

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

использование неквалифицированного имени по-прежнему поддерживается в 1.9, но устарело, и поддержка будет отброшена в 1.10.


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