¿Puedes detectar "arrastrar" en jQuery?


109

Tengo un latido que aparece cuando un usuario hace clic en un enlace.

El problema es que se puede hacer clic en ese mismo enlace y arrastrarlo para reorganizarlo. En este caso, no necesitaría que apareciera el palpitante. Solo necesita aparecer si realmente está esperando para ir a alguna parte.

¿Cómo puedo, con jQuery, crear un detector de eventos que solo permita que aparezca un palpitante si es un clic a través de un enlace , y no un clic y arrastrar?


¿Quizás OOT? Probé varios enfoques para arrastrar y soltar con jQuery, incluida la interfaz de usuario de jQuery, mi propio código con eventos mousedown, mouseup, mousemove y el que ha funcionado mejor es github.com/haberman/jdragdrop .
Rafael Vega

Aquí hay otra solución simple sin ningún marco pesado. blog.blakesimpson.co.uk/read/…
Programador químico

Respuestas:


225

En mousedown, comience a establecer el estado, si el evento mousemove se activa, regístrelo, finalmente en mouseup, verifique si el mouse se movió. Si se movió, lo hemos estado arrastrando. Si no nos hemos movido, es un clic.

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

Aquí hay una demostración: http://jsfiddle.net/W7tvD/1399/


1
hey ... ¿puedes ayudarme con esto? stackoverflow.com/questions/19703617/…
HIRA THAKUR

2
Es posible que desee agregar un umbral de arrastre para que sus clics no se interpreten como arrastres en el elemento "a". Solo busque una cierta cantidad de cambio en un evento xey mousemove.
Ash Blue

Impresionante, justo después de que el viento desenlazara mousemove puse mi código para que actúe tan pronto como se detectó el inicio del arrastre. ¡gracias!
Valamas

3
Descubrí que, en algunos casos y / o navegadores, mousemovese seguirán disparando al menos una vez incluso sin ningún movimiento, así que lo cambié para incrementar la variable en el movimiento y luego verifiqué un cierto umbral en mouseup jsfiddle.net/W7tvD/1649 Funciona como un encanto para mí ahora, ¡gracias!
Halfbit

27

Por alguna razón, las soluciones anteriores no me funcionaron. Fui con lo siguiente:

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

Puede ajustar el límite de distancia a lo que quiera, o incluso llevarlo hasta cero.


La mejor respuesta, me ayudó mucho. Solo un pensamiento: Math.sqrt no es realmente necesario, es mejor trabajar con distancias cuadradas (sqrt es lento, podría afectar la UX).
Bruno Ferreira

1
sqrtno es lento y no afectará a la UX, ni siquiera si lo hiciste cientos de veces.
NateS

Sí, preocúpese por la raíz cuadrada innecesaria en el bucle interno de su motor de física, no por su controlador de clic jquery ...
PeterT

19

¡Con jQuery UI simplemente haz esto!

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

  },
  drag: function() {

  },
  stop: function() {

  }
});

6
Necesita jquery-ui, pero es la forma más sencilla.
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");
});

Esta solución utiliza las funciones "on" y "off" para vincular y desvincular un evento mousemove (vincular y desvincular están en desuso). También puede detectar el cambio en las posiciones xey del mouse entre dos eventos mousemove.


3

Pruebe esto: muestra cuándo está el estado 'arrastrado'. ;) enlace de violín

$(function() {
    var isDragging = false;
    $("#status").html("status:");
    $("a")
    .mousedown(function() {
        $("#status").html("status: DRAGGED");        
    })
    .mouseup(function() {
        $("#status").html("status: dropped");   
    });

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

2

Me desvié de la respuesta aceptada para ejecutar solo cuando el clic se mantiene presionado y arrastrado .

Mi función se estaba ejecutando cuando no estaba presionando el mouse. Aquí está el código actualizado si también desea esta funcionalidad:

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

    }
);

1

Para esta forma más sencilla es tocar inicio, tocar mover y tocar final. Eso funciona tanto para PC como para dispositivos táctiles, solo compruébalo en la documentación de jquery y espero que esta sea la mejor solución para ti. buena suerte


1

Complemento jQuery basado en la respuesta de Simen Echholt. Lo llamé clic único.

/**
 * 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);
        });
    });
};

En uso:

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

^^


1

Asegúrese de establecer el atributo arrastrable del elemento en falso para que no tenga efectos secundarios al escuchar los eventos del mouseup:

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

Entonces, puedes usar 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;
  });
});

0

Tienes que configurar un temporizador. Cuando se agote el tiempo del temporizador, encienda el vibrador y registre el clic. Cuando se produce el arrastre, borre el temporizador para que nunca se complete.


1
..muy inteligente, ¿cómo detecta un arrastre?
Viaje

1
cuando configura el Draggable, debería haber un evento onDrag. Conéctelo allí.
Diodeus - James MacFarlane

0

Si está utilizando jQueryUI, hay un evento onDrag. Si no es así, adjunte su oyente a mouseup (), no haga clic en ().


1
¿Cómo diferenciaría mouseup entre arrastrar y hacer clic?
Viaje

Hmmm, sí, supongo que no lo pensé lo suficiente. Quizás pueda tener un oyente adjunto al mousedown que registre las coordenadas del mouse. Luego, si las coordenadas del mouse en mouseup son las mismas (o muy cercanas), considérelo un clic.
Quasipickle


La respuesta también tiene 4 años, considérelo.
Quasipickle

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

0

No tiene que configurar la variable, solo puede configurar si se está moviendo en el atributo de datos

$youtubeSlider.find('a')
    .on('mousedown', function (e) {
        $(this).data('moving', false);
    })
    .on('mousemove', function (e) {
        $(this).data('moving', true);
    })
    .on('mouseup', function (e) {
        if (!$(this).data('moving')) {
            // Open link
        }
    });

0

Necesitaba una función que siempre realizara un seguimiento de la posición del mouse y detectara el arrastre hacia la izquierda, derecha, arriba o abajo. Tampoco se activa al hacer clic, pero necesita un movimiento mínimo de 15px

/**
 * Check for drag when moved minimum 15px
 * Same time keep track of mouse position while dragging
 */
// Variables to be accessed outside in other functions
var dragMouseX;
var dragMouseY;
var myDragging = false; // true or false
var dragDirectionX = false; // left or right
var dragDirectionY = false; // top or bottom

$(document).on("mousedown", function(e) {
    // Reset some variables on mousedown
    var lastDirectionCheck = e.timeStamp;
    var dragStartX = e.pageX;
    var dragStartY = e.pageY;
    dragMouseX = e.pageX;
    dragMouseY = e.pageY;
    myDragging = false;
    dragDirectionX = false;
    dragDirectionY = false;

    // On the move
    $(document).on("mousemove", function(e) {
        dragMouseX = e.pageX;
        dragMouseY = e.pageY;

        // Recalculate drag direction every 200ms in case user changes his mind
        if (e.timeStamp > (lastDirectionCheck + 200)) {
            dragStartX = dragMouseX;
            dragStartY = dragMouseY;
            lastDirectionCheck = e.timeStamp;
        }

        // Check for drag when moved minimum 15px in any direction
        if (!myDragging && Math.abs(dragStartX - dragMouseX) > 15 || Math.abs(dragStartY - dragMouseY) > 15) {
            myDragging = true;
        }
        if (myDragging) {
            // Check drag direction X
            if (dragStartX > dragMouseX) dragDirectionX = 'left';
            if (dragStartX < dragMouseX) dragDirectionX = 'right';

            // Check drag direction Y
            if (dragStartY > dragMouseY) dragDirectionY = 'top';
            if (dragStartY < dragMouseY) dragDirectionY = 'bottom';

            // console.log(dragDirectionX + ' ' + dragDirectionY);
        }
    });
});

// Reset some variables again on mouseup
$(document).on("mouseup", function() {
    $(document).off("mousemove");
    myDragging = false;
    dragDirectionX = false;
    dragDirectionY = false;
});
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.