Запобігання події натискання за допомогою jQuery перетягуванням


85

У мене на сторінці є елементи, які можна перетягнути за допомогою jQuery. Чи мають ці елементи подію клацання, яка переходить на іншу сторінку (наприклад, звичайні посилання).

Який найкращий спосіб запобігти спрацьовуванню клацання при упущенні такого елемента, дозволяючи клацанню не перетягувати і не відпускати стан?

У мене проблема з сортувальними елементами, але я вважаю, що добре мати рішення для загального перетягування.

Я вирішив проблему для себе. Після цього я виявив, що таке саме рішення існує для Scriptaculous , але, можливо, хтось має кращий спосіб досягти цього.


Подібне / дублікат: stackoverflow.com/questions/3486760/…
Райан

Відповіді:


88

Рішення, яке добре працювало для мене і не вимагає тайм-ауту: (так, я трохи педантичний ;-)

Я додаю клас маркера до елемента при запуску перетягування, наприклад '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
    }
});

1
Корисно! Не працював у мене одним рухом, можливо, тому, що я возився в попередніх спробах того самого, і класи закінчувались на іншому елементі, ніж той, на який клацнули. проста сторінка була нормальною), і це теж працювало досить добре.
MSpreij

2
Це привело мене до мого рішення, я просто використовував функцію даних jQuery замість класу. Дякую.
Вільям

3
але браузер не запускає подію клацання кожного разу, коли ви
кидаєте

6
Щоб зберегти налаштування класу або даних, у обробнику подій кліку ви також можете використовувати: if (! $ (This) .is ('.
Ui-draggable-dragging

1
На жаль, вам не потрібен stop: function(event, ui) { $(this).removeClass('noclick'); }перетягуваний обробник? В іншому випадку, не перетягування кудись ще кудись заважає наступному клацанню на "вашому селекторі".
Bob Stein

41

Рішення полягає в тому, щоб додати обробник клацання, який запобіжить поширенню клацання на початку перетягування. А потім видаліть цей обробник після виконання падіння. Останню дію слід трохи відкласти, щоб запобігання клацанням спрацювало.

Розчин для сортування:

...
.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({
...
        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
здається, це не могло перешкодити для мене події кліків, я використовую jquery 1.9.1 та jquery.ui 1.10.3
aaron

1
дивно, що ти відповів на власне запитання, а воно навіть не працює, Саша ха-ха.

@aaron Ця відповідь нижче працює: http://stackoverflow.com/a/4572831/119765
lol

Ще один простий відповідь - просто місце й JQuery .click обробник () після того, як .draggable () stackoverflow.com/questions/18032136 / ...
JxAxMxIxN

1
якщо ви передасте помічник атрибута зі значенням "clone", він уникає ініціювання події для перетягнутого відсортованого елемента .. {helper: 'clone', start, stop ... і т. д.},
Luchux,

12

У мене була та сама проблема, я пробував кілька підходів, і жоден не працював у мене.

Рішення 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(); } );
    }
});

Це працює чудово, але не вдається в одному випадку - коли я йшов повноекранним onclick:

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

Так, це все - правильний порядок робить трюк - спочатку потрібно прив’язати функцію перетягування (), а потім клацнути (). Навіть коли я ставлю повноекранний перемикаючий код у події click (), він все одно не переходить на повноекранний при перетягуванні. Для мене ідеально!


1
Тільки одне, що працювало у мене (в IE11 / Edge), було рішення 4. Дякую!
Саймон

1
№4 є правильним і найпростішим рішенням для мене, без використання класів або змінних.
електротип

11

Я хотів би додати до цього, що, здається, запобігання події клацання працює лише в тому випадку, якщо подія клацання визначена ПІСЛЯ події, що перетягується чи сортується. Якщо клацання додано спочатку, воно активується при перетягуванні.


9

Я не дуже люблю користуватися таймерами або запобіганням, тож я зробив так:

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

Роксолід ..


Це було найкраще рішення для мене. У мене були проблеми з отриманням подій кліків для роботи над користувальницьким інтерфейсом jquery, який можна сортувати у мобільному веб-браузері за допомогою jquery.ui.touch.punch.js, але це вирішило це досить елегантно.
Годсміт

3

версія 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");
}
});

2
Здається, користувальницький інтерфейс jquery додає клас 'ui-sortable-helper' до елемента, який сортується. Отже, ви можете залишити клас 'noclick' і просто зробити if ($ (this) .hasClass ('ui-sortable-helper')). Більш лаконічний шлях
Метт Де Леон,

3

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

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

3

У користувацькому інтерфейсі jQuery елементи, які перетягуються, отримують клас "ui-draggable-dragging".
Тому ми можемо використовувати цей клас, щоб визначити, натискати чи ні, просто відкладіть подію.
Вам не потрібно використовувати функції зворотного виклику "старт" або "зупинка", просто виконайте:

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

Це ініціюється за допомогою "вказівника миші", а не "вилучення" або "клацання" - тому невелика затримка може бути не ідеальною, - але це простіше, ніж інші запропоновані тут рішення.


1

Після прочитання цього та кількох тем це було рішення, з яким я пішов.

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

1

У моєму випадку це працювало так:

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

0

Ви пробували відключити посилання за допомогою event.preventDefault (); у початковій події та повторному ввімкненні в події зупинки перетягування чи події падіння за допомогою unbind?


0

Тільки трохи зморшок, щоб додати відповіді, наведені вище. Мені довелося створити div, який містить елемент SalesForce, який можна перетягнути, але елемент SalesForce має дію onclick, визначену в html, за допомогою деякого з’єднання VisualForce.

Очевидно, що це порушує правило "визначити дію натискання після дії перетягування", тому в якості обхідного рішення я перевизначив дію елемента 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');
    }
});

Подія натискання батьків по суті приховує необхідність подвійного клацання дочірнього елемента, залишаючи недоторканим взаємодію з користувачем.


0

Я спробував так:

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

});

0

для мене допоміг передачу помічника в об'єкт options як:

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

Здається, елемент клонування dom, який перетягується, запобіг бурхливим подіям. Я не міг цього уникнути жодним випадком поширення, бульбашок тощо. Це було єдиним робочим рішенням для мене.


0

Події 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();" />

Так, я знаю. Не найчистіший спосіб, але ви зрозуміли ідею.


0

найпростішим та надійнішим рішенням? просто створіть прозорий елемент над вашим перетягуванням.

.click-passthrough {
  position: absolute;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background: transparent;
}

element.draggable({        
        start: function () {

        },
        drag: function(event, ui) {
            // important! if create the 'cover' in start, then you will not see click events at all
                  if (!element.find('.click-passthrough').length) {
                      element.append("<div class='click-passthrough'></div>");
                  }
        },
        stop: function() {
          // remove the cover
          element.find('.click-passthrough').remove();
        }
    });
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.