Ответ 1
Виджет draggable
не выставляет такое событие из коробки (пока). Вы можете изменить его и сохранить свою собственную версию или, лучше, вывести из нее новый виджет и реализовать там новое событие. Существует, однако, третий способ.
Из этого вопроса, мы знаем, что виджет хранит массив потенциально "спящих" элементов в свойстве snapElements
. В свою очередь, каждый элемент в этом массиве предоставляет свойство snapping
, которое является true
, если в данный момент привязанный к перехвату помощник привязан к этому элементу и false
в противном случае (помощник может привязать к нескольким элементам одновременно).
Массив snapElements
обновляется для каждого события drag
, поэтому он всегда обновляется в обработчиках drag
. Оттуда нам нужно только получить экземпляр виджета draggable
из связанного элемента с data() и вызвать его метод _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'...
}
});
Однако вышеприведенный код может быть улучшен. Как бы то ни было, событие 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, ключ data()
становится полнофункциональным именем виджета, с замененными точками на черточки. Соответственно, код, используемый выше для получения экземпляра виджета, становится следующим:
var draggable = $(this).data("ui-draggable");
Вместо:
var draggable = $(this).data("draggable");
Использование неквалифицированного имени по-прежнему поддерживается в 1.9, но устарело, а поддержка будет уменьшена в 1.10.