У меня есть элементы на странице, которые можно перетаскивать с помощью jQuery. Есть ли у этих элементов событие click, которое переходит на другую страницу (например, обычные ссылки).
Каков наилучший способ предотвратить срабатывание щелчка при удалении такого элемента, позволяя щелкнуть его без перетаскивания?
У меня есть проблема с сортируемыми элементами, но я думаю, что хорошо иметь решение для общего перетаскивания.
Решил для себя проблему. После этого я обнаружил, что такое же решение существует для Scriptaculous , но, возможно, у кого-то есть лучший способ добиться этого.
javascript
jquery
events
drag-and-drop
jquery-ui-sortable
Александр Яновец
источник
источник
Ответы:
Решение, которое хорошо сработало для меня и не требует тайм-аута: (да, я немного педантичен ;-)
Я добавляю класс маркера к элементу при запуске перетаскивания, например, «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 } });
источник
stop: function(event, ui) { $(this).removeClass('noclick'); }
перетаскиваемого обработчика? В противном случае не каждое перетаскивание в другое место помешает следующему щелчку по «вашему селектору».Решение состоит в том, чтобы добавить обработчик щелчка, который предотвратит распространение щелчка при начале перетаскивания. А затем удалите этот обработчик после выполнения сброса. Последнее действие следует немного отложить, чтобы сработала функция предотвращения кликов.
Решение для сортируемого:
... .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); } ... })
источник
У меня была та же проблема, и я пробовал несколько подходов, и ни один из них не помог мне.
Решение 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) { });
Да, вот и все - правильный порядок помогает - сначала вам нужно привязать событие draggable (), затем click (). Даже когда я помещал код переключения полноэкранного режима в событие click (), он все равно не переходил в полноэкранный режим при перетаскивании. Отлично для меня!
источник
Я хотел бы добавить к этому, что, похоже, предотвращение события щелчка работает, только если событие щелчка определено ПОСЛЕ перетаскиваемого или сортируемого события. Если щелчок добавлен первым, он активируется при перетаскивании.
источник
Мне не очень нравится использовать таймеры или предотвращение, поэтому я сделал следующее:
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; }
Скала..
источник
версия 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"); } });
источник
Возможный вариант ответа Саши без предотвращения дефолта:
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); },
источник
В пользовательском интерфейсе jQuery перетаскиваемым элементам присваивается класс «ui-draggable-dragging».
Таким образом, мы можем использовать этот класс, чтобы определить, щелкать или нет, просто отложив событие.
Вам не нужно использовать функции обратного вызова "start" или "stop", просто выполните:
$('#foo').on('mouseup', function () { if (! $(this).hasClass('ui-draggable-dragging')) { // your click function } });
Это запускается с помощью «mouseup», а не «mousedown» или «click» - поэтому есть небольшая задержка, может быть не идеально - но это проще, чем другие решения, предлагаемые здесь.
источник
Прочитав это и несколько тем, я выбрал это решение.
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; } });
источник
В моем случае это работало так:
$('#draggable').draggable({ start: function(event, ui) { $(event.toElement).one('click', function(e) { e.stopPropagation(); }); } });
источник
Вы пробовали отключить ссылку с помощью event.preventDefault (); в событии запуска и повторно включить его в событии остановки перетаскивания или событии отпускания с помощью отмены привязки?
источник
Немного морщин, чтобы добавить к приведенным выше ответам. Мне пришлось сделать div, который содержит перетаскиваемый элемент SalesForce, но у элемента SalesForce есть действие onclick, определенное в html через какой-то gobbledigook 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'); } });
Событие родительского щелчка по существу скрывает необходимость дважды щелкнуть дочерний элемент, оставляя без изменений взаимодействие с пользователем.
источник
Я пробовал вот так:
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); } });
источник
для меня помог передать помощника в объекте параметров как:
.sortable({ helper : 'clone', start:function(), stop:function(), ..... });
Кажется, что клонирование перетаскиваемого элемента dom предотвратило всплытие события. Я не мог избежать этого с помощью любого eventPropagation, всплывания и т. Д. Это было единственное рабочее решение для меня.
источник
События 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();" />
Да, я знаю. Не самый чистый способ, но идею вы поняли.
источник
самое простое и надежное решение? просто создайте прозрачный элемент поверх перетаскиваемого.
.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(); } });
источник