Предотвращение события click при перетаскивании jQuery

У меня есть элементы на странице, которые можно перетаскивать с помощью jQuery. Есть ли у этих элементов событие щелчка, которое переходит на другую страницу (например, обычные ссылки).

What is the best way to prevent click from firing on dropping such element while allowing clicking it is not dragged и drop state?

Каков наилучший способ предотвратить срабатывание щелчка при отбрасывании такого элемента, в то же время позволяя щелкнуть по нему, не перетаскивая и выбрасывая состояние? У меня есть эта проблема с сортируемыми элементами, но я думаю, что было бы хорошо иметь решение для общего перетаскивания.

Я решил проблему для себя. После этого я обнаружил, что то же самое решение существует для Scriptaculous, но, возможно, у кого-то есть лучший способ добиться этого.

Ответ 1

Решение состоит в том, чтобы добавить обработчик кликов, который предотвратит распространение нажатия на начало перетаскивания. И затем удалите этот обработчик после того, как произойдет сброс. Последнее действие должно быть задержано немного для предотвращения нажатия.

Решение для сортировки:

...
.sortable({
...
        start: function(event, ui) {
            ui.item.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.item.unbind("click.prevent");}, 300);
        }
...
})

Решение для draggable:

...
.draggable({
...
        start: function(event, ui) {
            ui.helper.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
        }
...
})

Ответ 2

Решение, которое хорошо работало для меня, и для этого не требуется тайм-аут: (да, я немного педантичен;)

Я добавляю класс маркера к элементу при запуске перетаскивания, например. 'Noclick. Когда элемент отбрасывается, срабатывает событие клика - точнее, если перетаскивание заканчивается, на самом деле его нельзя отбрасывать на действительную цель. В обработчике кликов я удаляю класс маркера, если он присутствует, иначе щелчок обрабатывается нормально.

$('your selector').draggable({
    start: function(event, ui) {
        $(this).addClass('noclick');
    }
});

$('your selector').click(function(event) {
    if ($(this).hasClass('noclick')) {
        $(this).removeClass('noclick');
    }
    else {
        // actual click event code
    }
});

Ответ 3

У меня была такая же проблема, и я пытался использовать несколько подходов, и никто не работал у меня.

Решение 1

$('.item').click(function(e)
{            
    if ( $(this).is('.ui-draggable-dragging') ) return false;
});  

ничего не делает для меня. Элемент будет нажат после завершения перетаскивания.

Решение 2 (Том де Бур)

$('.item').draggable(
{   
    stop: function(event, ui) 
    {
         $( event.originalEvent.target).one('click', function(e){ e.stopImmediatePropagation(); } );
    }
});

Это работает отлично, но не удается в одном случае - когда я шел в полноэкранном режиме:

var body = $('body')[0];     
req = body.requestFullScreen || body.webkitRequestFullScreen || body.mozRequestFullScreen;
req.call(body); 

Решение 3 (Саша Яновец)

 $('.item').draggable({
        start: function(event, ui) {
            ui.helper.bind("click.prevent",
                function(event) { event.preventDefault(); });
        },
        stop: function(event, ui) {
            setTimeout(function(){ui.helper.unbind("click.prevent");}, 300);
        }
})

Это не работает для меня.

Решение 4- единственное, что отлично работало

$('.item').draggable(
{   
});
$('.item').click(function(e)
{  
});

Да, это правильный порядок делает трюк - сначала вам нужно связать draggable(), а затем щелкнуть(). Даже когда я помещаю полноэкранный код переключения в событие click(), он все равно не переходит в полноэкранный режим при перетаскивании. Идеально для меня!

Ответ 4

Я хотел бы добавить к этому, что кажется, что предотвращение события click работает только в том случае, если определено событие click ПОСЛЕ перетаскиваемого или сортируемого события. Если клик добавлен первым, он активируется при перетаскивании.

Ответ 5

Я обнаружил, что используя стандартную функцию щелчка jQuery:

$("#element").click(function(mouseEvent){ // click event });

отлично работает в jQuery UI. Событие клика не будет выполняться при перетаскивании.:)

Ответ 6

Я не очень люблю использовать таймеры или предотвращать, поэтому я сделал это:

var el, dragged

el = $( '#some_element' );

el.on( 'mousedown', onMouseDown );
el.on( 'mouseup', onMouseUp );
el.draggable( { start: onStartDrag } );

onMouseDown = function( ) {
  dragged = false;
}

onMouseUp = function( ) {
  if( !dragged ) {
    console.log('no drag, normal click')
  }
}

onStartDrag = function( ) {
  dragged = true;
}

Rocksolid..

Ответ 7

lex82, но для .sortable()

 start: function(event, ui){
 ui.item.find('.ui-widget-header').addClass('noclick');
 },

и вам может понадобиться только:

 start: function(event, ui){
 ui.item.addClass('noclick');
 },

и вот что я использую для переключения:

$("#datasign-widgets .ui-widget-header").click(function(){
if ($(this).hasClass('noclick')) {
$(this).removeClass('noclick');

}
else {
$(this).next().slideToggle();
$(this).find('.ui-icon').toggleClass("ui-icon-minusthick").toggleClass("ui-icon-plusthick");
}
});

Ответ 8

Возможная альтернатива для ответа Саши без предупреждения по умолчанию:

var tmp_handler;
.sortable({
        start : function(event,ui){
            tmp_handler = ui.item.data("events").click[0].handler;
            ui.item.off();
        },
        stop : function(event,ui){
            setTimeout(function(){ui.item.on("click", tmp_handler)}, 300);
        },

Ответ 9

В пользовательском интерфейсе jQuery перетаскиваемые элементы получают класс "ui-draggable-dragging".
Поэтому мы можем использовать этот класс, чтобы определить, нужно ли кликать или нет, просто задерживайте событие.
Вам не нужно использовать функции "start" или "stop" callback, просто выполните:

$('#foo').on('mouseup', function () {
    if (! $(this).hasClass('ui-draggable-dragging')) {
        // your click function
    }
});

Это срабатывает от "mouseup", а не "mousedown" или "click", поэтому небольшая задержка может быть не идеальной, но это проще, чем другие предлагаемые здесь решения.

Ответ 10

После прочтения этого и нескольких потоков это было решением, с которым я пошел.

var dragging = false;
$("#sortable").mouseover(function() {
    $(this).parent().sortable({
        start: function(event, ui) {
            dragging = true;
        },
        stop: function(event, ui) {
            // Update Code here
        }
    })
});
$("#sortable").click(function(mouseEvent){
    if (!dragging) {
        alert($(this).attr("id"));
    } else {
        dragging = false;
    }
});

Ответ 11

Вы пытались отключить связь, используя event.preventDefault(); в событии запуска и повторного включения его в событии остановки перетаскивания или событии drop с помощью unbind?

Ответ 12

Немного морщин, чтобы добавить к приведенным выше ответам. Мне пришлось создать div, содержащий элемент SalesForce, который можно перетаскивать, но элемент SalesForce имеет действие onclick, определенное в html, через некоторый графический образ VisualForce.

Очевидно, это нарушает правило "определять действие click после правила перетаскивания", так как обходным путем я переопределил действие элемента SalesForce, которое должно быть запущено "onDblClick", и использовал этот код для контейнера div:

$(this).draggable({
        zIndex: 999,
        revert: true,
        revertDuration: 0,
        start: function(event, ui) {
                   $(this).addClass('noclick');
                }
});

$(this).click(function(){
    if( $(this).hasClass('noclick'))
    {
        $(this).removeClass('noclick');
    }
    else
    {
        $(this).children(":first").trigger('dblclick');
    }
});

Событие родительского щелчка по существу скрывает необходимость двойного щелчка по дочернему элементу, оставив его неповрежденным.

Ответ 13

Я пробовал вот так:

var dragging = true; 

$(this).click(function(){
  if(!dragging){
    do str...
  }
});

$(this).draggable({
  start: function(event, ui) {
      dragging = true;
  },

  stop: function(event, ui) {
      setTimeout(function(){dragging = false;}, 300);
  }

});

Ответ 14

В моем случае это сработало вот так:

$('#draggable').draggable({
  start: function(event, ui) {
    $(event.toElement).one('click', function(e) { e.stopPropagation(); });
  }
});

Ответ 15

для меня помогло передать помощник в настройках объекта как:

.sortable({
   helper : 'clone', 
   start:function(), 
   stop:function(),
   .....
});

Кажется, что клонирующий элемент dom, который перетаскивается, предотвращает всплеск события. Я не мог избежать этого с любым событием: размножением, пузырями и т.д. Это было единственное рабочее решение для меня.

Ответ 16

События onmousedown и onmouseup работали в одном из моих небольших проектов.

var mousePos = [0,0];
function startClick()
{
    mousePos = [event.clientX,event.clientY];
}
        
function endClick()
{
    if ( event.clientX != mousePos[0] && event.clientY != mousePos[1] )
    {
        alert( "DRAG CLICK" );
    }
    else
    {
        alert( "CLICK" );
    }
}
<img src=".." onmousedown="startClick();" onmouseup="endClick();" />