J'ai des éléments sur la page qui peuvent être déplacés avec jQuery. Ces éléments ont-ils un événement de clic qui navigue vers une autre page (liens ordinaires par exemple).
Quelle est la meilleure façon d'empêcher le clic de se déclencher lors de la chute d'un tel élément tout en permettant de cliquer sur l'état du glisser-déposer?
J'ai ce problème avec les éléments triables mais je pense qu'il est bon d'avoir une solution pour le glisser-déposer général.
J'ai résolu le problème moi-même. Après cela, j'ai trouvé que la même solution existe pour Scriptaculous , mais peut-être que quelqu'un a un meilleur moyen d'y parvenir.
javascript
jquery
events
drag-and-drop
jquery-ui-sortable
Alexandre Yanovets
la source
la source
Réponses:
Une solution qui a bien fonctionné pour moi et qui ne nécessite pas de timeout: (oui je suis un peu pédant ;-)
J'ajoute une classe de marqueur à l'élément au début du glissement, par exemple «noclick». Lorsque l'élément est déposé, l'événement de clic est déclenché - plus précisément si le glissement se termine, il n'est en fait pas nécessaire de le déposer sur une cible valide. Dans le gestionnaire de clics, je supprime la classe de marqueur si elle est présente, sinon le clic est géré 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 } });
la source
stop: function(event, ui) { $(this).removeClass('noclick'); }
dans le gestionnaire déplaçable? Sinon, chaque glisser-déposer ailleurs ne contrariera pas le prochain clic sur «votre sélecteur».La solution consiste à ajouter un gestionnaire de clic qui empêchera le clic de se propager au début du glissement. Et puis supprimez ce gestionnaire après la suppression. La dernière action doit être un peu retardée pour que la prévention des clics fonctionne.
Solution pour triable:
... .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 glisser:
... .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); } ... })
la source
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é une fois le glissement terminé.
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 - lorsque j'allais en plein écran en cliquant sur:
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); } })
Cela ne fonctionne pas pour moi.
Solution 4 - la seule qui a bien fonctionné
$('.item').draggable( { }); $('.item').click(function(e) { });
Oui, c'est tout - le bon ordre fait l'affaire - vous devez d'abord lier l'événement draggable () puis click (). Même lorsque j'ai mis du code de basculement en plein écran dans l'événement click (), il ne passait toujours pas en plein écran lors du glissement. Parfait pour moi!
la source
Je voudrais 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 déplaçable ou triable. Si le clic est ajouté en premier, il est activé par glisser.
la source
Je n'aime pas vraiment utiliser les minuteries ou la prévention, alors 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; }
Solide comme le roc..
la source
version de lex82 mais pour .sortable ()
start: function(event, ui){ ui.item.find('.ui-widget-header').addClass('noclick'); },
et vous n'aurez peut-être besoin que de:
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"); } });
la source
Une alternative possible à la réponse de Sasha sans empêcher le défaut:
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); },
la source
Dans jQuery UI, les éléments glissés reçoivent la classe "ui-draggable-dragging".
On peut donc utiliser cette classe pour déterminer s'il faut cliquer ou non, simplement 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é par "mouseup", plutôt que "mousedown" ou "click" - il y a donc un léger retard, peut-être pas parfait - mais c'est plus facile que d'autres solutions suggérées ici.
la source
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; } });
la source
Dans mon cas, cela a fonctionné comme ceci:
$('#draggable').draggable({ start: function(event, ui) { $(event.toElement).one('click', function(e) { e.stopPropagation(); }); } });
la source
Avez-vous essayé de désactiver le lien en utilisant event.preventDefault (); dans l'événement de démarrage et le réactiver dans l'événement de glisser arrêté ou de déposer à l'aide de la suppression?
la source
Juste une petite ride à ajouter aux réponses données ci-dessus. J'ai dû créer un div contenant un élément SalesForce pouvant être déplacé, mais l'élément SalesForce a une action onclick définie dans le html via un gobbledigook VisualForce.
Évidemment, cela enfreint la règle «définir l'action de clic après l'action de glisser», donc comme solution de contournement, j'ai redéfini l'action de l'élément SalesForce pour qu'elle soit déclenchée «onDblClick», et 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 masque essentiellement la nécessité de double-cliquer sur l'élément enfant, laissant ainsi l'expérience utilisateur intacte.
la source
J'ai essayé comme ça:
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); } });
la source
pour moi, j'ai aidé à passer l'assistant dans l'objet d'options comme:
.sortable({ helper : 'clone', start:function(), stop:function(), ..... });
Semble l'élément dom de clonage qui est glissé a empêché le bouillonnement de l'événement. Je ne pouvais pas l'éviter avec n'importe quel eventPropagation, bouillonnement, etc. C'était la seule solution qui fonctionnait pour moi.
la source
Les événements onmousedown et onmouseup ont fonctionné dans l'un de mes petits projets.
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();" />
Oui je sais. Ce n'est pas la manière la plus propre, mais vous voyez l'idée.
la source
la solution la plus simple et la plus robuste? créez simplement un élément transparent sur votre draggable.
.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(); } });
la source