Ngăn chặn sự kiện nhấp chuột bằng cách kéo và thả jQuery


85

Tôi có các phần tử trên trang có thể kéo bằng jQuery. Các phần tử này có sự kiện nhấp chuột điều hướng đến một trang khác không (ví dụ: các liên kết thông thường).

Cách tốt nhất để ngăn nhấp chuột kích hoạt khi thả phần tử đó trong khi cho phép nhấp chuột vào nó không ở trạng thái kéo và thả là gì?

Tôi gặp vấn đề này với các phần tử có thể sắp xếp nhưng nghĩ rằng sẽ tốt nếu có giải pháp cho việc kéo và thả chung.

Tôi đã giải quyết vấn đề cho chính mình. Sau đó, tôi thấy rằng có giải pháp tương tự cho Scriptaculous , nhưng có thể ai đó có cách tốt hơn để đạt được điều đó.


Tương tự / trùng lặp: stackoverflow.com/questions/3486760/…
Ryan

Câu trả lời:


88

Một giải pháp hoạt động tốt đối với tôi và không yêu cầu thời gian chờ: (vâng, tôi hơi khó hiểu ;-)

Tôi thêm một lớp đánh dấu vào phần tử khi quá trình kéo bắt đầu, ví dụ: 'noclick'. Khi phần tử được thả xuống, sự kiện nhấp chuột được kích hoạt - chính xác hơn là nếu quá trình kéo kết thúc, thực tế nó không cần phải được thả vào một mục tiêu hợp lệ. Trong trình xử lý nhấp chuột, tôi xóa lớp đánh dấu nếu có, nếu không, nhấp chuột được xử lý bình thường.

$('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
Hữu ích! Không hiệu quả với tôi trong một lần, có thể là do tôi đã gây rối trong những lần thử trước đó với cùng một thứ và các lớp kết thúc trên một phần tử khác với phần tử được nhấp .. nhưng dù sao, tôi đã sử dụng một biến toàn cục (điều này cực kỳ trang đơn giản là ok), và điều đó cũng hoạt động khá tốt.
MSpreij

2
Điều này dẫn tôi đến giải pháp của mình, tôi chỉ sử dụng hàm dữ liệu jQuery thay vì một lớp. Cảm ơn.
William

3
nhưng trình duyệt sẽ không kích hoạt sự kiện nhấp chuột mỗi khi bạn thả phần tử
puchu

6
Để lưu cài đặt một lớp hoặc dữ liệu, trong trình xử lý sự kiện nhấp chuột, bạn cũng có thể sử dụng: if (! $ (This) .is ('. Ui-draggable-drag')) {... click action}
ChrisV

1
Rất tiếc, bạn không muốn stop: function(event, ui) { $(this).removeClass('noclick'); }sử dụng trình xử lý có thể kéo? Nếu không, mọi thao tác kéo-n-thả ở nơi khác sẽ không cản trở lần nhấp tiếp theo vào 'bộ chọn của bạn'.
Bob Stein,

41

Giải pháp là thêm trình xử lý nhấp chuột sẽ ngăn nhấp chuột lan truyền khi bắt đầu kéo. Và sau đó loại bỏ trình xử lý đó sau khi thả được thực hiện. Hành động cuối cùng nên được trì hoãn một chút để ngăn chặn nhấp chuột hoạt động.

Giải pháp để có thể sắp xếp:

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

Giải pháp cho có thể kéo:

...
.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
dường như điều này không thể ngăn cản sự kiện click cho tôi, im sử dụng jquery 1.9.1 và jquery.ui 1.10.3
aaron

1
Kỳ lạ là bạn đã trả lời câu hỏi của chính mình, và nó thậm chí không hoạt động, Sasha lol.

@aaron câu trả lời này bên dưới hoạt động: http://stackoverflow.com/a/4572831/119765
lol

Một câu trả lời đơn giản khác - chỉ cần đặt trình xử lý jQuery .click () sau .draggable () stackoverflow.com/questions/18032136/…
JxAxMxIxN 19/09/16

1
nếu bạn chuyển trình trợ giúp thuộc tính với giá trị 'clone', nó sẽ tránh kích hoạt sự kiện cho mục được sắp xếp kéo .. {helper: 'clone', start, stop ... etc},
Luchux

12

Tôi đã gặp vấn đề tương tự và đã thử nhiều cách tiếp cận nhưng không có cách nào phù hợp với tôi.

Giải pháp 1

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

không làm gì cho tôi. Mục đang được nhấp sau khi kéo xong.

Giải pháp 2 (của Tom de Boer)

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

Điều này hoạt động tốt nhưng không thành công trong một trường hợp - khi tôi chuyển sang chế độ toàn màn hình khi nhấp chuột:

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

Giải pháp 3 (bởi 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);
        }
})

Điều này không làm việc cho tôi.

Giải pháp 4- giải pháp duy nhất hoạt động tốt

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

Đúng vậy - đúng thứ tự thực hiện thủ thuật - trước tiên bạn cần phải ràng buộc draggable () sau đó nhấp vào sự kiện (). Ngay cả khi tôi đặt mã chuyển đổi toàn màn hình trong sự kiện click (), nó vẫn không chuyển sang chế độ toàn màn hình khi kéo. Hoàn hảo cho tôi!


1
Chỉ có một giải pháp phù hợp với tôi (trong IE11 / Edge) là giải pháp 4. Cảm ơn!
Simon

1
# 4 là giải pháp chính xác và đơn giản nhất đối với tôi, mà không cần sử dụng các lớp hoặc biến.
electrotype

11

Tôi muốn thêm vào điều này rằng có vẻ như việc ngăn chặn sự kiện nhấp chuột chỉ hoạt động nếu sự kiện nhấp chuột được xác định SAU sự kiện có thể kéo hoặc có thể sắp xếp. Nếu lần nhấp được thêm vào trước, nó sẽ được kích hoạt khi kéo.


9

Tôi thực sự không thích sử dụng bộ hẹn giờ hoặc ngăn chặn, vì vậy những gì tôi đã làm là:

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

Sỏi đá..


Đây là giải pháp tốt nhất cho tôi. Tôi đã gặp sự cố khi các sự kiện nhấp chuột hoạt động trên giao diện người dùng jquery có thể sắp xếp trong trình duyệt web trên thiết bị di động bằng jquery.ui.touch.punch.js, nhưng điều này đã giải quyết nó khá tốt.
Godsmith

3

phiên bản của lex82 nhưng dành cho .sortable ()

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

và bạn có thể chỉ cần:

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

và đây là những gì tôi đang sử dụng cho chuyển đổi:

$("#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
Dường như giao diện người dùng jquery gắn lớp 'ui-sortable-helper' vào mục đang được sắp xếp. Vì vậy, bạn có thể bỏ qua lớp 'noclick' và chỉ thực hiện nếu ($ (this) .hasClass ('ui-sortable-helper')). Hơn là cách ngắn gọn
Matt De Leon

3

Một giải pháp thay thế khả thi cho câu trả lời của Sasha mà không ngăn chặn sự vỡ nợ:

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

Trong giao diện người dùng jQuery, các phần tử đang được kéo có lớp "ui-draggable-drag".
Do đó, chúng ta có thể sử dụng lớp này để xác định xem có nhấp chuột hay không, chỉ cần trì hoãn sự kiện.
Bạn không cần phải sử dụng các hàm gọi lại "bắt đầu" hoặc "dừng", chỉ cần thực hiện:

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

Điều này được kích hoạt từ "mouseup" chứ không phải "mousedown" hoặc "click" - do đó, có một chút chậm trễ, có thể không hoàn hảo - nhưng nó dễ dàng hơn các giải pháp khác được đề xuất ở đây.


1

Sau khi đọc qua điều này và một vài chủ đề, đây là giải pháp tôi đã sử dụng.

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

Trong trường hợp của tôi, nó hoạt động như thế này:

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

0

Bạn đã thử tắt liên kết bằng event.preventDefault () chưa; trong sự kiện bắt đầu và bật lại nó trong sự kiện kéo dừng hoặc sự kiện thả bằng cách sử dụng unbind?


0

Chỉ cần một chút nếp nhăn để thêm vào các câu trả lời được đưa ra ở trên. Tôi đã phải tạo một div có chứa phần tử SalesForce có thể kéo được, nhưng phần tử SalesForce có hành động onclick được xác định trong html thông qua một số VisualForce gobbledigook.

Rõ ràng điều này vi phạm quy tắc "xác định hành động nhấp sau hành động kéo", vì vậy, để giải quyết vấn đề này, tôi đã xác định lại hành động của phần tử SalesForce để được kích hoạt "onDblClick" và sử dụng mã này cho div vùng chứa:

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

Sự kiện nhấp chuột của phụ huynh về cơ bản ẩn nhu cầu nhấp đúp vào phần tử con, giữ nguyên trải nghiệm người dùng.


0

Tôi đã thử như thế này:

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

đối với tôi đã giúp chuyển trợ giúp trong đối tượng tùy chọn dưới dạng:

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

Có vẻ như phần tử dom nhân bản được kéo đã ngăn cản sự sôi nổi của sự kiện. Tôi không thể tránh được nó với bất kỳ sự kiện nào Có sự lan truyền, sủi bọt, v.v. Đây là giải pháp hiệu quả duy nhất đối với tôi.


0

Các sự kiện onmousedown và onmouseup hoạt động trong một trong những dự án nhỏ hơn của tôi.

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();" />

Vâng tôi biết. Không phải là cách sạch sẽ nhất, nhưng bạn có được ý tưởng.


0

giải pháp dễ dàng và mạnh mẽ nhất? chỉ cần tạo phần tử trong suốt trên có thể kéo của bạn.

.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();
        }
    });
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.