Mam na stronie elementy, które można przeciągać za pomocą jQuery. Czy te elementy mają zdarzenie kliknięcia, które prowadzi do innej strony (na przykład zwykłe linki).
Jaki jest najlepszy sposób, aby zapobiec uruchomieniu kliknięcia przy upuszczeniu takiego elementu, podczas gdy kliknięcie nie jest w stanie przeciągnij i upuść?
Mam ten problem z elementami, które można sortować, ale myślę, że dobrze jest mieć rozwiązanie do ogólnego przeciągania i upuszczania.
Rozwiązałem problem samodzielnie. Potem odkryłem, że to samo rozwiązanie istnieje dla Scriptaculous , ale może ktoś ma lepszy sposób, aby to osiągnąć.
javascript
jquery
events
drag-and-drop
jquery-ui-sortable
Alexander Yanovets
źródło
źródło
Odpowiedzi:
Rozwiązanie, które działało dobrze i nie wymaga przerwy: (tak, jestem trochę pedantyczny ;-)
Dodam klasę markera do elementu, gdy zaczyna się przeciąganie, np. „Noclick”. Po upuszczeniu elementu wyzwalane jest zdarzenie kliknięcia - a dokładniej, jeśli przeciąganie się kończy, w rzeczywistości nie trzeba go upuszczać na prawidłowy cel. W module obsługi kliknięcia usuwam klasę znacznika, jeśli jest obecna, w przeciwnym razie kliknięcie jest obsługiwane normalnie.
$('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 } });
źródło
stop: function(event, ui) { $(this).removeClass('noclick'); }
w programie obsługi do przeciągania? W przeciwnym razie nie każde przeciągnięcie i upuszczenie w innym miejscu nie pokrzyżuje kolejnego kliknięcia „Twojego selektora”.Rozwiązaniem jest dodanie modułu obsługi kliknięcia, który uniemożliwi propagację kliknięcia na początku przeciągania. A następnie usuń ten program obsługi po wykonaniu upuszczenia. Ostatnia czynność powinna zostać nieco opóźniona, aby zapobieganie kliknięciom działało.
Rozwiązanie do sortowania:
... .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); } ... })
Rozwiązanie do przeciągania:
... .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); } ... })
źródło
Miałem ten sam problem i próbowałem wielu podejść i żadna nie działała dla mnie.
Rozwiązanie 1
$('.item').click(function(e) { if ( $(this).is('.ui-draggable-dragging') ) return false; });
nic dla mnie nie robi. Element jest klikany po zakończeniu przeciągania.
Rozwiązanie 2 (autorstwa Toma de Boera)
$('.item').draggable( { stop: function(event, ui) { $( event.originalEvent.target).one('click', function(e){ e.stopImmediatePropagation(); } ); } });
Działa to dobrze, ale zawodzi w jednym przypadku - kiedy przechodziłem na pełny ekran po kliknięciu:
var body = $('body')[0]; req = body.requestFullScreen || body.webkitRequestFullScreen || body.mozRequestFullScreen; req.call(body);
Rozwiązanie 3 (autorstwa Sashy 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); } })
To nie działa dla mnie.
Rozwiązanie 4 - jedyne, które działało dobrze
$('.item').draggable( { }); $('.item').click(function(e) { });
Tak, to wszystko - właściwa kolejność załatwia sprawę - najpierw musisz powiązać zdarzenie draggable (), a następnie click (). Nawet gdy umieściłem kod przełączający na pełny ekran w zdarzeniu click (), nadal nie przechodził do pełnego ekranu podczas przeciągania. Idealne dla mnie!
źródło
Chciałbym dodać do tego, że wydaje się, że zapobieganie zdarzeniu kliknięcia działa tylko wtedy, gdy zdarzenie kliknięcia jest zdefiniowane PO zdarzeniu, które można przeciągać lub sortować. Jeśli kliknięcie zostanie dodane jako pierwsze, zostanie aktywowane po przeciągnięciu.
źródło
Naprawdę nie lubię używać timerów ani zapobiegać, więc zrobiłem to:
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; }
Twardy jak skała..
źródło
Wersja lex82, ale dla .sortable ()
start: function(event, ui){ ui.item.find('.ui-widget-header').addClass('noclick'); },
i możesz potrzebować tylko:
start: function(event, ui){ ui.item.addClass('noclick'); },
a oto, czego używam do przełączania:
$("#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"); } });
źródło
Możliwa alternatywa dla odpowiedzi Sashy bez zapobiegania niewypłacalności:
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); },
źródło
W interfejsie użytkownika jQuery przeciągane elementy otrzymują klasę „ui-draggable-dragging”.
Możemy zatem użyć tej klasy do określenia, czy kliknąć, czy nie, po prostu opóźnić zdarzenie.
Nie musisz używać funkcji wywołania zwrotnego „start” lub „stop”, po prostu wykonaj:
$('#foo').on('mouseup', function () { if (! $(this).hasClass('ui-draggable-dragging')) { // your click function } });
Jest to wywoływane przez „najechanie myszą”, a nie „wciśnięcie myszy” lub „kliknięcie” - więc występuje niewielkie opóźnienie, może nie być idealne - ale jest to łatwiejsze niż inne sugerowane tutaj rozwiązania.
źródło
Po przeczytaniu tego i kilku wątków było to rozwiązanie, które wybrałem.
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; } });
źródło
W moim przypadku działało tak:
$('#draggable').draggable({ start: function(event, ui) { $(event.toElement).one('click', function(e) { e.stopPropagation(); }); } });
źródło
Czy próbowałeś wyłączyć łącze za pomocą event.preventDefault (); w zdarzeniu początkowym i ponowne włączenie go w zdarzeniu zatrzymanym przez przeciąganie lub upuszczanie za pomocą polecenia unbind?
źródło
Tylko mała zmarszczka, aby dodać do odpowiedzi podanych powyżej. Musiałem zrobić div, który zawiera przeciągany element SalesForce, ale element SalesForce ma akcję onclick zdefiniowaną w html za pomocą jakiegoś VisualForce gobbledigook.
Oczywiście narusza to zasadę „zdefiniuj akcję kliknięcia po akcji przeciągania”, więc jako obejście ponownie zdefiniowałem akcję elementu SalesForce, która ma być wyzwalana „onDblClick”, i użyłem tego kodu dla elementu div kontenera:
$(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'); } });
Zdarzenie kliknięcia rodzica zasadniczo ukrywa potrzebę dwukrotnego kliknięcia elementu podrzędnego, pozostawiając nienaruszone wrażenia użytkownika.
źródło
Próbowałem tak:
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); } });
źródło
pomogło mi przekazanie helpera w obiekcie opcji jako:
.sortable({ helper : 'clone', start:function(), stop:function(), ..... });
Wydaje się, że przeciąganie elementu dom do klonowania zapobiegło propagacji zdarzenia. Nie mogłem tego uniknąć w przypadku propagacji zdarzeń, bulgotania itp. To było dla mnie jedyne działające rozwiązanie.
źródło
Wydarzenia onmousedown i onmouseup działały w jednym z moich mniejszych projektów.
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();" />
Tak, wiem. Nie jest to najczystszy sposób, ale masz pomysł.
źródło
najłatwiejsze i najmocniejsze rozwiązanie? po prostu stwórz przezroczysty element na swoim możliwym do przeciągnięcia.
.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(); } });
źródło