माउस "क्लिक" और "ड्रैग" को कैसे अलग करें


165

मैं का उपयोग jQuery.clickराफेल ग्राफ पर माउस क्लिक करें घटना को संभालने के लिए, इस बीच, मैं माउस को संभालने की ज़रूरत dragघटना, माउस खींचें के होते हैं mousedown, mouseupऔर mousemoveराफेल में।

यह भेद करना मुश्किल है clickऔर dragक्योंकि clickइसमें भी mousedown& mouseup, मैं माउस को "क्लिक" और माउस को "ड्रैग" में कैसे भेद कर सकता हूँ?

जवाबों:


192

मुझे लगता है कि अंतर यह है कि mousemoveबीच में mousedownऔर mouseupएक खींचें में है, लेकिन एक क्लिक में नहीं।

आप ऐसा कुछ कर सकते हैं:

const element = document.createElement('div')
element.innerHTML = 'test'
document.body.appendChild(element)
let moved
let downListener = () => {
    moved = false
}
element.addEventListener('mousedown', downListener)
let moveListener = () => {
    moved = true
}
element.addEventListener('mousemove', moveListener)
let upListener = () => {
    if (moved) {
        console.log('moved')
    } else {
        console.log('not moved')
    }
}
element.addEventListener('mouseup', upListener)

// release memory
element.removeEventListener('mousedown', downListener)
element.removeEventListener('mousemove', moveListener)
element.removeEventListener('mouseup', upListener)

38
बस एक ड्रैग को ट्रिगर करने के लिए मूसमोव पर न्यूनतम डेल्टा एक्स या वाई की आवश्यकता होती है। एक टिक
मूसोव की

12
मुझे नहीं लगता कि यह अब तक के सबसे आखिरी क्रोम में काम करता है: 32.0.1700.72 Mousemove फायर करता है कि आप माउस को
हिलाते हैं

17
इस स्वीकृत उत्तर कोड में XY माउस निर्देशांक के बीच एक न्यूनतम डेल्टा स्थिति शामिल होनी चाहिए mousedownऔर झंडे को सेट mouseupकरने के लिए mousemoveघटना को सुनने के बजाय । इसके अलावा, यह मुद्दा @mrjrdnthms ने उल्लेख किया ठीक हैं
Billybobbonnet

2
मैं क्रोम 56.0.2924.87 (64-बिट) चला रहा हूं और मैं उन मुद्दों का अनुभव नहीं कर रहा हूं जो @mrjrdnthms वर्णन कर रहे हैं।
jkupczak

1
@AmerllicA यह शायद बग नहीं है, लेकिन अपेक्षित व्यवहार है, लेकिन यदि आप अपने उपयोग के मामले में दिलचस्प हैं, तो आप
मूषक और मूसलीव

37

मामले में आप पहले से ही jQuery का उपयोग कर रहे हैं:

var $body = $('body');
$body.on('mousedown', function (evt) {
  $body.on('mouseup mousemove', function handler(evt) {
    if (evt.type === 'mouseup') {
      // click
    } else {
      // drag
    }
    $body.off('mouseup mousemove', handler);
  });
});

यहां तक ​​कि अगर आप क्लिक करते समय माउस को थोड़ा सा हिलाते हैं, तो यह कहेगा drag। अन्य टिप्पणियों की तरह एक अतिरिक्त गुंजाइश कह रही है कि यहां जरूरत हो सकती है।
चिमो

@ चियोमो जो मैं उपयोग कर रहा हूं वह पहले से माउस की स्थिति को संग्रहीत कर रहा है evtऔर दूसरे की स्थिति के साथ तुलना कर रहा है evt, इसलिए, उदाहरण के लिए if (evt.type === 'mouseup' || Math.abs(evt1.pageX - evt2.pageX) < 5 || Math.abs(evt1.pageY - evt2.pageY) < 5) { ...:।
गुस्तावो रोड्रिग्स

1
मैंने इस प्रश्न के अन्य सभी उत्तरों की कोशिश की, और यह केवल एक ही है जिसने काम किया है .on('mouseup mousemove touchend touchmove'), और इसके शीर्ष पर स्थिति वेरिएबल्स को सेट नहीं किया है। महान समाधान!
थेहड़मन

कभी-कभी जब मैं माउसअप के बजाय एक तत्व "evt.type" रिटर्न "mousemove" पर क्लिक करता था। मैं उस मुद्दे को कैसे हल कर सकता हूं?
Libu मैथ्यू

27

क्लीनर ES2015

let drag = false;

document.addEventListener('mousedown', () => drag = false);
document.addEventListener('mousemove', () => drag = true);
document.addEventListener('mouseup', () => console.log(drag ? 'drag' : 'click'));

किसी भी कीड़े का अनुभव नहीं किया, जैसा कि अन्य टिप्पणी करते हैं।


6
यह छोटे चाल के साथ क्लिक से ग्रस्त है।
अमीर केबी

1
@AmirKeibi आप मूसमव्स की संख्या की गणना कर सकते हैं (या दो क्लिक के बीच की दूरी की गणना भी कर सकते हैं, लेकिन यह ओवरकिल होगा)
रेनफॉल

19

यह अच्छी तरह से काम करना चाहिए। स्वीकृत उत्तर के समान (हालांकि jQuery का उपयोग करते हुए), लेकिन isDraggingध्वज केवल तभी रीसेट किया जाता है जब नई माउस स्थिति उस mousedownघटना से भिन्न हो । स्वीकृत उत्तर के विपरीत, यह क्रोम के हाल के संस्करणों पर काम करता है, जहां mousemoveमाउस ले जाया गया था या नहीं इसकी परवाह किए बिना निकाल दिया जाता है।

var isDragging = false;
var startingPos = [];
$(".selector")
    .mousedown(function (evt) {
        isDragging = false;
        startingPos = [evt.pageX, evt.pageY];
    })
    .mousemove(function (evt) {
        if (!(evt.pageX === startingPos[0] && evt.pageY === startingPos[1])) {
            isDragging = true;
        }
    })
    .mouseup(function () {
        if (isDragging) {
            console.log("Drag");
        } else {
            console.log("Click");
        }
        isDragging = false;
        startingPos = [];
    });

mousemoveयदि आप थोड़ी सहिष्णुता जोड़ना चाहते हैं , तो आप समन्वय की जांच को भी समायोजित कर सकते हैं (यानी क्लिक के रूप में छोटे आंदोलनों का इलाज करें, ड्रग्स नहीं)।


12

यदि आप Rxjs का उपयोग करने की तरह महसूस करते हैं :

var element = document;

Rx.Observable
  .merge(
    Rx.Observable.fromEvent(element, 'mousedown').mapTo(0),
    Rx.Observable.fromEvent(element, 'mousemove').mapTo(1)
  )
  .sample(Rx.Observable.fromEvent(element, 'mouseup'))
  .subscribe(flag => {
      console.clear();
      console.log(flag ? "drag" : "click");
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://unpkg.com/@reactivex/rxjs@5.4.1/dist/global/Rx.js"></script>

यह एक सीधा क्लोन है जो @ wong2 ने अपने उत्तर में किया था, लेकिन RxJ में परिवर्तित हो गया।

का भी रोचक उपयोग samplesampleऑपरेटर स्रोत से नवीनतम मान ले (होगा mergeकी mousedownऔर mousemove) है और यह फेंकना जब भीतरी नमूदार ( mouseup) उत्सर्जन करता है।


22
मैं अपना सारा कोड वेधशालाओं के साथ लिखता हूं ताकि मेरे बॉस मुझे बदलने के लिए किसी और को काम पर न रख सकें।
रिएक्टगुलर

11

जैसा कि mrjrdnthms ने स्वीकार किए गए उत्तर पर अपनी टिप्पणी में कहा है, यह अब क्रोम पर काम नहीं करता है (यह हमेशा मूसमव को फायर करता है), मैंने Chrome व्यवहार को संबोधित करने के लिए गुस्तावो के उत्तर (जब से मैं jQuery का उपयोग कर रहा हूं) को अनुकूलित कर लिया है।

var currentPos = [];

$(document).on('mousedown', function (evt) {

   currentPos = [evt.pageX, evt.pageY]

  $(document).on('mousemove', function handler(evt) {

    currentPos=[evt.pageX, evt.pageY];
    $(document).off('mousemove', handler);

  });

  $(document).on('mouseup', function handler(evt) {

    if([evt.pageX, evt.pageY].equals(currentPos))
      console.log("Click")
    else
      console.log("Drag")

    $(document).off('mouseup', handler);

  });

});

Array.prototype.equalsसमारोह इस से आता है जवाब


1
यह लगभग मेरे लिए काम करता था, लेकिन मुझे [evt.pageX, evt.pageY].equals()कमांड से एक त्रुटि मिली । मैं उस के साथ बदल दिया (evt.pageX === currentPos[0] && evt.pageY===currentPos[1]), और सब अच्छा था। :)
user2441511

equalsकोड की जरूरत है मेरी पोस्ट के नीचे स्थित लिंक से जोड़े जाने के लिए
फ्रांसिस्को एक्विनो

आह, यह बताते हैं। धन्यवाद।
user2441511

1
मैं तर्क को समझ नहीं सकता। क्यों आप अपडेट करते हैं currentPosपर mousemove? इसका मतलब यह नहीं है कि आप क्लिक के रूप में कुछ ड्रग्स का इलाज करेंगे?
निर्वाण-मुकुट

1
यदि आप "mouseup"अभी भी माउस ले जाते समय आग नहीं लगाते हैं।
चिमो

9

ये सभी समाधान या तो छोटे माउस आंदोलनों पर टूटते हैं, या अतिरंजित होते हैं।

यहां दो ईवेंट श्रोताओं का उपयोग करते हुए एक सरल अनुकूलनीय समाधान है। डेल्टा पिक्सेल की वह दूरी है जिसे आपको एक क्लिक के बजाय ड्रैग के रूप में वर्गीकृत करने के लिए कोड के लिए अप और डाउन घटनाओं के बीच क्षैतिज या लंबवत चलना चाहिए। ऐसा इसलिए है क्योंकि कभी-कभी आप माउस या अपनी उंगली को उठाने से पहले कुछ पिक्स हिलाते हैं।

const delta = 6;
let startX;
let startY;

element.addEventListener('mousedown', function (event) {
  startX = event.pageX;
  startY = event.pageY;
});

element.addEventListener('mouseup', function (event) {
  const diffX = Math.abs(event.pageX - startX);
  const diffY = Math.abs(event.pageY - startY);

  if (diffX < delta && diffY < delta) {
    // Click!
  }
});

अब तक का सबसे अच्छा जवाब!
जियोर्जियो टेंपेस्टा

हाय @andreyrd, क्या मुझे पता है कि इसके लिए क्या deltaउपयोग किया जाता है? यह मोबाइल डिवाइस में नल के साथ कुछ करना है?
हज़ीक

1
@ हाज़ीक मुझे लगता है कि शीर्ष समाधानों की टिप्पणियों में वर्णित लोगों deltaका उपयोग "एक टिक
मूसवे के

1
मैंने स्पष्टीकरण के साथ उत्तर को अपडेट किया। मूल रूप से यदि आपकी उंगली 6 पिक्सेल से कम है, तो भी यह एक क्लिक के रूप में गिना जाएगा। यदि यह 6 या अधिक पिक्सेल ले जाता है, तो यह एक ड्रैग के रूप में गिना जाएगा।
andreyrd

5

खींचें का पता लगाने के लिए 5 पिक्सेल x / y थ्रेसहोल्ड के साथ jQuery का उपयोग करना:

var dragging = false;
$("body").on("mousedown", function(e) {
  var x = e.screenX;
  var y = e.screenY;
  dragging = false;
  $("body").on("mousemove", function(e) {
    if (Math.abs(x - e.screenX) > 5 || Math.abs(y - e.screenY) > 5) {
      dragging = true;
    }
  });
});
$("body").on("mouseup", function(e) {
  $("body").off("mousemove");
  console.log(dragging ? "drag" : "click");
});

2

अगर सिर्फ ड्रैग केस को फ़िल्टर करना है, तो इसे इस तरह करें:

var moved = false;
$(selector)
  .mousedown(function() {moved = false;})
  .mousemove(function() {moved = true;})
  .mouseup(function(event) {
    if (!moved) {
        // clicked without moving mouse
    }
  });

1

DeltaX और DeltaY के साथ शुद्ध जेएस

इस DeltaX और DeltaY के रूप में सुझाव में एक टिप्पणी द्वारा सुझाए गए निराशा के अनुभव से बचने के लिए जब एक टिक मूसमव के कारण एक ड्रैग ऑपरेशन पर क्लिक करने और प्राप्त करने की कोशिश की जाती है।

    deltaX = deltaY = 2;//px
    var element = document.getElementById('divID');
    element.addEventListener("mousedown", function(e){
        if (typeof InitPageX == 'undefined' && typeof InitPageY == 'undefined') {
            InitPageX = e.pageX;
            InitPageY = e.pageY;
        }

    }, false);
    element.addEventListener("mousemove", function(e){
        if (typeof InitPageX !== 'undefined' && typeof InitPageY !== 'undefined') {
            diffX = e.pageX - InitPageX;
            diffY = e.pageY - InitPageY;
            if (    (diffX > deltaX) || (diffX < -deltaX)
                    || 
                    (diffY > deltaY) || (diffY < -deltaY)   
                    ) {
                console.log("dragging");//dragging event or function goes here.
            }
            else {
                console.log("click");//click event or moving back in delta goes here.
            }
        }
    }, false);
    element.addEventListener("mouseup", function(){
        delete InitPageX;
        delete InitPageY;
    }, false);

   element.addEventListener("click", function(){
        console.log("click");
    }, false);

1

OSM मैप पर सार्वजनिक कार्रवाई के लिए (क्लिक पर मार्कर की स्थिति) प्रश्न था: 1) माउस की अवधि को कैसे निर्धारित किया जाए-> अप (आप प्रत्येक क्लिक के लिए एक नया मार्कर बनाने की कल्पना नहीं कर सकते) और 2) माउस नीचे जाने के दौरान-> ऊपर (यानी उपयोगकर्ता मानचित्र खींच रहा है)।

const map = document.getElementById('map');

map.addEventListener("mousedown", position); 
map.addEventListener("mouseup", calculate);

let posX, posY, endX, endY, t1, t2, action;

function position(e) {

  posX = e.clientX;
  posY = e.clientY;
  t1 = Date.now();

}

function calculate(e) {

  endX = e.clientX;
  endY = e.clientY;
  t2 = (Date.now()-t1)/1000;
  action = 'inactive';

  if( t2 > 0.5 && t2 < 1.5) { // Fixing duration of mouse down->up

      if( Math.abs( posX-endX ) < 5 && Math.abs( posY-endY ) < 5 ) { // 5px error on mouse pos while clicking
         action = 'active';
         // --------> Do something
      }
  }
  console.log('Down = '+posX + ', ' + posY+'\nUp = '+endX + ', ' + endY+ '\nAction = '+ action);    

}

0

दूरी आधारित सीमा का उपयोग करते हुए कक्षा आधारित वेनिला जेएस का उपयोग कर एक और समाधान

private initDetectDrag(element) {
    let clickOrigin = { x: 0, y: 0 };
    const dragDistanceThreshhold = 20;

    element.addEventListener('mousedown', (event) => {
        this.isDragged = false
        clickOrigin = { x: event.clientX, y: event.clientY };
    });
    element.addEventListener('mousemove', (event) => {
        if (Math.sqrt(Math.pow(clickOrigin.y - event.clientY, 2) + Math.pow(clickOrigin.x - event.clientX, 2)) > dragDistanceThreshhold) {
            this.isDragged = true
        }
    });
}

और वर्ग में जोड़ें (SOMESLIDER_ELEMENT भी वैश्विक होने के लिए दस्तावेज़ हो सकता है):

private isDragged: boolean;
constructor() {
    this.initDetectDrag(SOMESLIDER_ELEMENT);
    this.doSomeSlideStuff(SOMESLIDER_ELEMENT);
    element.addEventListener('click', (event) => {
        if (!this.sliderIsDragged) {
            console.log('was clicked');
        } else {
            console.log('was dragged, ignore click or handle this');
        }
    }, false);
}

0

यदि आप किसी विशिष्ट तत्व के क्लिक या ड्रैग व्यवहार की जांच करना चाहते हैं, तो आप शरीर की बात सुने बिना ऐसा कर सकते हैं।

$(document).ready(function(){
  let click;
  
  $('.owl-carousel').owlCarousel({
    items: 1
  });
  
  // prevent clicks when sliding
  $('.btn')
    .on('mousemove', function(){
      click = false;
    })
    .on('mousedown', function(){
      click = true;
    });
    
  // change mouseup listener to '.content' to listen to a wider area. (mouse drag release could happen out of the '.btn' which we have not listent to). Note that the click will trigger if '.btn' mousedown event is triggered above
  $('.btn').on('mouseup', function(){
    if(click){
      $('.result').text('clicked');
    } else {
      $('.result').text('dragged');
    }
  });
});
.content{
  position: relative;
  width: 500px;
  height: 400px;
  background: #f2f2f2;
}
.slider, .result{
  position: relative;
  width: 400px;
}
.slider{
  height: 200px;
  margin: 0 auto;
  top: 30px;
}
.btn{
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  height: 100px;
  background: #c66;
}
.result{
  height: 30px;
  top: 10px;
  text-align: center;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/owl.carousel.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/OwlCarousel2/2.3.4/assets/owl.carousel.min.css" />
<div class="content">
  <div class="slider">
    <div class="owl-carousel owl-theme">
      <div class="item">
        <a href="#" class="btn" draggable="true">click me without moving the mouse</a>
      </div>
      <div class="item">
        <a href="#" class="btn" draggable="true">click me without moving the mouse</a>
      </div>
    </div>
    <div class="result"></div>
  </div>
  
</div>


0

@Przemek के उत्तर से,

function listenClickOnly(element, callback, threshold=10) {
  let drag = 0;
  element.addEventListener('mousedown', () => drag = 0);
  element.addEventListener('mousemove', () => drag++);
  element.addEventListener('mouseup', e => {
    if (drag<threshold) callback(e);
  });
}

listenClickOnly(
  document,
  () => console.log('click'),
  10
);

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.