Riesci a rilevare il "trascinamento" in jQuery?


109

Ho un throbber che deve apparire quando un utente fa clic su un collegamento.

Il problema è che lo stesso collegamento può essere cliccato e trascinato per essere riorganizzato. In questo caso, non avrei bisogno che apparisse il throbber. Deve apparire solo se sta effettivamente aspettando di andare da qualche parte.

Come posso, con jQuery, creare un listener di eventi che consenta la visualizzazione di un throbber solo se è un clic su un collegamento e non un clic e trascina?


Forse OOT? Ho provato diversi approcci per il trascinamento della selezione con jQuery, inclusa l'interfaccia utente di jQuery, il mio codice con eventi mousedown, mouseup, mousemove e quello che ha funzionato meglio è github.com/haberman/jdragdrop .
Rafael Vega

Ecco un'altra semplice soluzione senza alcun quadro pesante. blog.blakesimpson.co.uk/read/…
Chemical Programmer

Risposte:


225

Su mousedown, inizia a impostare lo stato, se l'evento mousemove viene attivato registralo, infine su mouseup, controlla se il mouse si è mosso. Se si è spostato, lo stiamo trascinando. Se non ci siamo spostati, è 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();
    }
});

Ecco una demo: http://jsfiddle.net/W7tvD/1399/


1
hey..can mi aiuti con questo stackoverflow.com/questions/19703617/...
HIRA THAKUR

2
Potresti voler aggiungere una soglia di trascinamento in modo che i tuoi clic non vengano interpretati come trascinamenti sull'elemento "a". Cerca solo una certa quantità di cambiamento in un evento di rimozione del mouse xey.
Ash Blue,

Fantastico, subito dopo che il vento sblocca mousemove ho attivato il mio codice non appena è stato rilevato l'inizio del trascinamento. grazie!
Valamas

3
Ho scoperto che in alcuni casi e / o browser, mousemoveverrà comunque attivato almeno una volta anche senza alcun movimento, quindi l'ho modificato per incrementare la variabile in movimento e quindi verificare una certa soglia su mouseup jsfiddle.net/W7tvD/1649 Funziona come un fascino per me ora, grazie!
halfbit

27

Per qualche motivo, le soluzioni di cui sopra non funzionavano per me. Sono andato con quanto segue:

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

Puoi modificare il limite di distanza a tuo piacimento o addirittura portarlo a zero.


La migliore risposta, mi ha aiutato molto. Solo un pensiero: Math.sqrt non è davvero necessario, è meglio lavorare con distanze quadrate (sqrt è lento, potrebbe influenzare l'UX).
Bruno Ferreira

1
sqrtnon è lento e non influenzerà l'UX, nemmeno se l'hai fatto centinaia di volte.
NateS

Sì, preoccupati per la radice quadrata non necessaria nel loop interno del tuo motore fisico, non per il gestore dei clic jquery ...
PeterT

19

Con jQuery UI basta farlo!

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

  },
  drag: function() {

  },
  stop: function() {

  }
});

6
Hai bisogno di jquery-ui, ma è il modo più semplice.
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");
});

Questa soluzione utilizza le funzioni "on" e "off" per associare un evento di annullamento dell'associazione di un mousemove (l'associazione e l'annullamento dell'associazione sono deprecate). Puoi anche rilevare il cambiamento nelle posizioni xey del mouse tra due eventi di rimozione del mouse.


3

Prova questo: mostra quando è stato "trascinato". ;) collegamento violino

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

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

2

Mi sono allontanato dalla risposta accettata per eseguire solo quando il clic viene TENUTO e trascinato .

La mia funzione era in esecuzione quando non tenevo premuto il mouse. Ecco il codice aggiornato se vuoi anche questa funzionalità:

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

In questo modo più semplice è toccare l'inizio, toccare lo spostamento e toccare la fine. Funziona sia per PC che per dispositivi touch, controllalo nella documentazione di jquery e spero che questa sia la soluzione migliore per te. in bocca al lupo


1

Plugin jQuery basato sulla risposta di Simen Echholt. L'ho chiamato clic singolo.

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

In uso:

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

^^


1

Assicurati di impostare l' attributo trascinabile dell'elemento su false in modo da non avere effetti collaterali quando ascolti gli eventi del mouseup:

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

Quindi, puoi usare 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

Devi impostare un timer. Quando il timer scade, avvia il throbber e registra il clic. Quando si verifica il trascinamento, azzera il timer in modo che non si completi mai.


1
..molto intelligente, come si fa a rilevare un trascinamento?
Viaggio

1
quando si imposta il trascinabile, dovrebbe esserci un evento onDrag. Collegalo lì.
Diodeus - James MacFarlane

0

Se stai usando jQueryUI, c'è un evento onDrag. In caso contrario, collega il tuo ascoltatore a mouseup (), non a fare clic su ().


1
In che modo il mouseup distinguerebbe tra trascinamento e clic?
Viaggio

Hmmm - sì, immagino di non averci pensato abbastanza. Forse puoi avere un ascoltatore collegato a mousedown che registra le coordinate del mouse. Quindi se le coordinate del mouse su mouseup sono le stesse (o molto vicine), consideralo un click-through.
Quasipickle


La risposta è anche di 4 anni - consideralo.
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

Non è necessario impostare la variabile, puoi semplicemente impostare se si sta spostando nell'attributo dati

$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

Avevo bisogno di una funzione che tenga sempre traccia della posizione del mouse e rilevi il trascinamento a sinistra, a destra, in alto e in basso. Inoltre non si attiva al clic, ma richiede uno spostamento minimo di 15 px

/**
 * 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;
});
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.