Prévenir l'événement de clic avec jQuery drag and drop

j'ai un élément sur la page qui est draggabe avec jQuery. Ces éléments ont un clic événement qui navigue vers une autre page (liens ordinaires par exemple).

Quelle est la meilleure façon d'empêcher le clic de tirer sur la chute d'un tel élément, tout en permettant de le cliquer dans l'état de non glisser-déposer?

j'ai ce problème avec sortable éléments, mais pense qu'il est bon d'avoir la solution générale de glisser-déposer.

j'ai résolu le problème pour moi. Après cela trouvé que la même solution existe pour Scriptaculous , mais peut-être quelqu'un a une meilleure façon d'atteindre cela.

76
demandé sur Community 2009-11-20 19:25:10

14 réponses

une solution qui a bien fonctionné pour moi et qui ne nécessite pas de temps mort: (oui je suis un peu pédant ; -)

j'ajoute une classe marqueur à l'élément lorsque le déplacement commence, par exemple 'noclick'. Lorsque l'élément est supprimé, l'événement de clic est déclenché -- plus précisément si le déplacement se termine, en fait il n'a pas besoin d'être abandonné sur une cible valide. Dans le gestionnaire de clic, je supprime la classe de marqueur si elle est présente, sinon le clic est manipulé normalement.

$('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
    }
});
85
répondu lex82 2011-02-02 12:25:27

Solution est d'ajouter le gestionnaire de clic qui empêchera le clic de se propager au début de la traînée. Puis retirez du gestionnaire après la chute est effectuée. La dernière action devrait être retardée un peu pour que la prévention de clic fonctionne.

Solution pour sortable:

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

Solution pour égouttage:

...
.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);
        }
...
})
38
répondu Alexander Yanovets 2009-11-20 16:26:36

j'aimerais ajouter à cela qu'il semble empêcher l'événement de clic ne fonctionne que si l'événement de clic est défini après l'événement draggable ou sortable. Si le clic est ajouté en premier, il est activé sur la traînée.

11
répondu kasakka 2010-03-15 13:34:49

j'ai eu le même problème et j'ai essayé plusieurs approches et aucune n'a fonctionné pour moi.

Solution 1

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

ne fait rien pour moi. L'élément est cliqué après ce déplacement est effectué.

Solution 2 (par Tom De Boer)

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

cela fonctionne très bien mais échoue dans un cas - quand j'allais plein écran onclick:

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

Solution 3 (par Sasha Yanovets)

 $('.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);
        }
})

ça ne marche pas pour moi.

Solution 4 - le seul qui a fonctionné très bien

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

ouais, c'est ça - le bon de commande fait l'affaire - vous avez d'abord besoin de se lier draggable (), puis cliquez sur() de l'événement. Même quand j'ai mis le code de basculement du plein écran dans click (), il n'est pas allé sur le plein écran quand glisser. Parfait pour moi!

10
répondu Tom 2015-03-28 12:44:20

Je n'aime pas vraiment utiliser de minuteries ou de prévention, donc ce que j'ai fait est ceci:

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..

9
répondu Tim Baas 2012-11-15 08:48:17

j'ai trouvé que l'utilisation de la fonction de clic jQuery standard:

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

fonctionne très bien dans jQuery UI. L'événement de clic ne sera pas exécuté lorsque le glisser-déposer. :)

9
répondu Norm 2013-08-18 15:45:12

la version de lex82 mais pour .sortable ()

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

et que vous avez besoin est:

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

et voici ce que j'utilise pour la bascule:

$("#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");
}
});
3
répondu orolo 2011-01-10 20:24:09

une alternative possible pour la réponse de Sasha sans prévenir la défaillance:

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
répondu Matt Styles 2012-11-09 19:35:19

dans jQuery UI, les éléments traînés sont classés dans la classe"ui-draggable-dragging".

Nous pouvons donc utiliser cette classe pour déterminer s'il faut cliquer ou non, il suffit de retarder l'événement.

Vous n'avez pas besoin d'utiliser les fonctions de rappel "start" Ou "stop", faites simplement:

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

ceci est déclenché à partir de "mouseup", plutôt que "mousedown" ou "click" - donc il ya un léger retard, pourrait ne pas être parfait - mais il est plus facile que d'autres solutions sont suggérées ici.

3
répondu lsrwLuke 2017-03-04 18:32:41

après avoir lu ceci et quelques fils c'était la solution avec laquelle je suis allé.

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
répondu jwdreger 2014-09-09 17:11:13

avez-vous essayé de désactiver le lien En utilisant event.preventDefault(); dans le début de l'événement et de le réactiver dans les glisser arrêté de l'événement ou de la baisse de l'événement à l'aide de délier?

0
répondu alienonland 2009-11-20 16:29:11

juste une petite ride à ajouter aux réponses données ci-dessus. J'ai dû faire un div qui contient un élément SalesForce modulable, mais L'élément SalesForce a une action onclick définie dans le html à travers un certain VisualForce gobbledigook.

évidemment, cela viole la règle "définir l'action click après l'action drag", alors comme solution de contournement, j'ai redéfini L'action de L'élément SalesForce pour qu'elle soit déclenchée "onDblClick", et j'ai utilisé ce code pour le conteneur 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');
    }
});

l'événement de clic du parent cache essentiellement le besoin de double-cliquer l'élément enfant, laissant l'expérience utilisateur intacte.

0
répondu geekbrit 2013-05-15 15:01:16

j'ai essayé comme ceci:

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
répondu sun 2015-05-17 03:23:41

dans mon cas, il a fonctionné comme ceci:

$('#draggable').draggable({
  start: function(event, ui) {
    $(event.toElement).one('click', function(e) { e.stopPropagation(); });
  }
});
0
répondu user3165434 2015-08-03 13:28:58