你能在jQuery中检测“拖动”吗?

119

当用户点击链接时,我想要一个 throbber 出现。

问题在于,同一个链接可能会被点击并拖动以重新排列。在这种情况下,我不需要 throbber 出现,只有在等待跳转到某个地方时才需要出现。

如何使用 jQuery 创建事件监听器,仅在点击链接进行跳转时 允许 throbber 出现,而不是点击并拖动呢?


也许可以尝试一下OOT?我已经尝试过几种使用jQuery进行拖放的方法,包括jQuery UI、我的自己编写的mousedown、mouseup和mousemove事件代码以及最好用的方法是https://github.com/haberman/jdragdrop。 - Rafael Vega
这里有另一个简单的解决方案,没有任何繁重的框架。http://blog.blakesimpson.co.uk/read/51-swipe-js-detect-touch-direction-and-distance - Chemical Programmer
15个回答

240

在mousedown事件上,设置状态。如果触发了mousemove事件,则记录它,在mouseup事件中检查鼠标是否移动过。如果鼠标移动过,我们就拖动了。如果没有移动,那就是一个点击事件。

var isDragging = false;
$("a")
.mousedown(function() {
    isDragging = false;
})
.mousemove(function() {
    isDragging = true;
 })
.mouseup(function() {
    var wasDragging = isDragging;
    isDragging = false;
    if (!wasDragging) {
        $("#throbble").toggle();
    }
});

这里是一个演示:http://jsfiddle.net/W7tvD/1399/


1
嘿,你能帮我解决这个问题吗?http://stackoverflow.com/questions/19703617/replace-mousemove-by-mousedrag/19703798?noredirect=1#19703798 - HIRA THAKUR
3
你可能想要添加一个拖动阈值,这样你的点击就不会被解释为对"a"元素的拖动。只需查找在x和y的mousemove事件中发生的一定量变化即可。 - Ash Blue
太棒了,就在鼠标移动后解除绑定,我把我的代码放在检测到拖动开始的那一刻立即执行。谢谢你! - Valamas
3
我发现在某些情况下和/或某些浏览器中,即使没有移动鼠标,mousemove 仍会至少触发一次,因此我改为在移动时增加变量,然后在 mouseup 上检查一个特定的阈值。http://jsfiddle.net/W7tvD/1649/ 现在对我非常有效,谢谢! - halfbit

27

由于某些原因,上述解决方案对我不起作用。 我采用了以下解决方案:

$('#container').on('mousedown', function(e) {
    $(this).data('p0', { x: e.pageX, y: e.pageY });
}).on('mouseup', function(e) {
    var p0 = $(this).data('p0'),
        p1 = { x: e.pageX, y: e.pageY },
        d = Math.sqrt(Math.pow(p1.x - p0.x, 2) + Math.pow(p1.y - p0.y, 2));

    if (d < 4) {
        alert('clicked');
    }
})

您可以调整距离限制,使其符合您的需求,甚至可以将其降至零。


最佳答案,对我帮助很大。只是一个想法:Math.sqrt并不是必要的,最好使用平方距离(sqrt速度较慢,可能会影响用户体验)。 - Bruno Ferreira
2
sqrt 不会很慢,也不会影响用户体验,即使您重复使用了数百次。 - NateS
1
不要担心你的 jQuery 点击处理程序,而是要关注你的物理引擎内部循环中不必要的平方根... - PeterT

25

只需使用jQuery UI就可以做到这一点!

$( "#draggable" ).draggable({
  start: function() {

  },
  drag: function() {

  },
  stop: function() {

  }
});

6
你需要jquery-ui,但这是最简单的方法。 - Ortomala Lokni

5
$(".draggable")
.mousedown(function(e){
    $(this).on("mousemove",function(e){
        var p1 = { x: e.pageX, y: e.pageY };
        var p0 = $(this).data("p0") || p1;
        console.log("dragging from x:" + p0.x + " y:" + p0.y + "to x:" + p1.x + " y:" + p1.y);
        $(this).data("p0", p1);
    });
})
.mouseup(function(){
    $(this).off("mousemove");
});

此解决方案使用"on"和"off"函数来绑定和解除绑定鼠标移动事件("bind"和"unbind"已被弃用)。您还可以检测两个鼠标移动事件之间鼠标X和Y位置的变化。


这种解决方案的问题是每次 mousedown 事件都会向 this 添加另一个事件处理程序,导致该函数的代码体被执行多次并逐渐增加。 - LuKenneth

3
尝试这个:它显示了何时处于“拖动”状态。;) fiddle链接
$(function() {
    var isDragging = false;
    $("#status").html("status:");
    $("a")
    .mousedown(function() {
        $("#status").html("status: DRAGGED");        
    })
    .mouseup(function() {
        $("#status").html("status: dropped");   
    });

    $("ul").sortable();
});

2
// here is how you can detect dragging in all four directions
var isDragging = false;
$("some DOM element").mousedown(function(e) {
    var previous_x_position = e.pageX;
    var previous_y_position = e.pageY;

    $(window).mousemove(function(event) {
        isDragging = true;
        var x_position = event.pageX;
        var y_position = event.pageY;

        if (previous_x_position < x_position) {
            alert('moving right');
        } else {
            alert('moving left');
        }
        if (previous_y_position < y_position) {
            alert('moving down');
        } else {
            alert('moving up');
        }
        $(window).unbind("mousemove");
    });
}).mouseup(function() {
    var wasDragging = isDragging;
    isDragging = false;
    $(window).unbind("mousemove");
});

2
我从已接受的答案中分支出来,仅在按住并拖动鼠标时运行。当我没有按住鼠标时,我的函数会运行。如果您也想要此功能,请使用以下更新后的代码:
var isDragging = false;
var mouseDown = false;

$('.test_area')
    .mousedown(function() {
        isDragging = false;
        mouseDown = true;
    })
    .mousemove(function(e) {
        isDragging = true;

        if (isDragging === true && mouseDown === true) {
            my_special_function(e);
        }
     })
    .mouseup(function(e) {

        var wasDragging = isDragging;

        isDragging = false;
        mouseDown = false;

        if ( ! wasDragging ) {
            my_special_function(e);
        }

    }
);

2

请确保将元素的draggable属性设置为false,这样在监听mouseup事件时就不会产生副作用:

<div class="thing" draggable="false">text</div>

然后,您可以使用jQuery:

$(function() {
  var pressed, pressX, pressY,
      dragged,
      offset = 3; // helps detect when the user really meant to drag

  $(document)
  .on('mousedown', '.thing', function(e) {
    pressX = e.pageX;
    pressY = e.pageY;
    pressed = true;
  })
  .on('mousemove', '.thing', function(e) {
    if (!pressed) return;
    dragged = Math.abs(e.pageX - pressX) > offset ||
              Math.abs(e.pageY - pressY) > offset;
  })
  .on('mouseup', function() {
    dragged && console.log('Thing dragged');
    pressed = dragged = false;
  });
});

1
基于Simen Echholt的答案,这是一个jQuery插件。我将其称为single click。
/**
 * jQuery plugin: Configure mouse click that is triggered only when no mouse move was detected in the action.
 * 
 * @param callback
 */
jQuery.fn.singleclick = function(callback) {
    return $(this).each(function() {
        var singleClickIsDragging = false;
        var element = $(this);

        // Configure mouse down listener.
        element.mousedown(function() {
            $(window).mousemove(function() {
                singleClickIsDragging = true;
                $(window).unbind('mousemove');
            });
        });

        // Configure mouse up listener.
        element.mouseup(function(event) {
            var wasDragging = singleClickIsDragging;
            singleClickIsDragging = false;
            $(window).unbind('mousemove');
            if(wasDragging) {
                return;
            }

            // Since no mouse move was detected then call callback function.
            callback.call(element, event);
        });
    });
};

正在使用中:

element.singleclick(function(event) {
    alert('Single/simple click!');
});

^^


1
晚来一步,但这段代码也可以检测触摸事件(移动设备、平板电脑)。
$(".draggable").on('touchstart mousedown', function(ev) {
    ev.preventDefault();
    $(this).on("touchmove mousemove",function(e){
        var x = e.pageX || e.changedTouches[0].pageX;
        var y = e.pageY || e.changedTouches[0].pageY;
        var p1 = { x: x, y: y };
        var p0 = $(this).data("p0") || p1;
        console.log("dragging from x:" + p0.x + " y:" + p0.y + "to x:" + p1.x + " y:" + p1.y);
        $(this).data("p0", p0);
    });
}).on('touchend mouseup', function(ev) {
    ev.preventDefault();
    $(this).off("touchmove mousemove");
});

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接