25

I don't know whether it is only Chrome problem (can't check now), however let's try the following piece of code, where we bind two events to some element:

$("div").on({
    mousemove: function(e) {
        console.log("move");
    },
    click: function(e) {
        console.log("click");
    }
});

If we try to click the element, we'll find that for some reason mousemove event fires immediately after click, so in console we have:

>> ...
>> click
>> move

DEMO: http://jsfiddle.net/gKqVt/

Note, that mousedown and mouseup events work by the same scenario.

I saw many questions on SO about the same problem, but none (in my search) gave the straightforward idea what to do in order to fire the click event only.

VisioN
  • 143,310
  • 32
  • 282
  • 281
  • 2
    Mice move all the time. The problem is your program depending on not moving the mouse when clicking. – stark Jan 26 '13 at 16:10
  • Seems the mousemove event fires on click as well, did'nt know that, and tried logging the event, and can't find anything different then a regular mousemove to seperate them either. Hard nut to crack this one? Here's one way to work around it [**FIDDLE**](http://jsfiddle.net/gKqVt/2/) ... – adeneo Jan 26 '13 at 16:12
  • Why is this a problem? The user can legitimately move the mouse and click so that a "real" move follows a click as far as your code is concerned. It should be able to handle this without issues. – Jon Jan 26 '13 at 16:12
  • 1
    On Chrome 25 (OSX) 'click' fires on click and 'move' fires on move. No problem whatsoever. – Oleg Jan 26 '13 at 16:12
  • 1
    When using a touchpad (laptop) `mousemove` is not triggered (Chrome 24, OSX). So either you really move the mouse while clicking or input devices are treated differently or it is fixed in that version. Firefox does not trigger `mousemove` either. – Felix Kling Jan 26 '13 at 16:13
  • 1
    I see this issue on Chrome 23, but not on Firefox 18 or IE8. This is using a Lenovo touchpad. (Update: I just upgraded Chrome to 24 on Win7 and still see the issue) – Ben McCormick Jan 26 '13 at 16:16
  • @Jon In my current experiments I log all events to array in order to work with them later. The basic idea is to do logging in the most compact way, and extra events just add extra weight. – VisioN Jan 26 '13 at 16:16
  • 1
    FF 17 on OSX also works as @Oleg described. – bfavaretto Jan 26 '13 at 16:17
  • @Felix Looks like it is treated differently on different devices, since I definitely do not move the mouse when do the click, I'm fine `:D` – VisioN Jan 26 '13 at 16:19
  • In the jQuery doc they say _However, high frequency events such as mousemove or scroll can fire dozens of times per second, and in those cases it becomes more important to use events judiciously. Performance can be increased by reducing the amount of work done in the handler itself, caching information needed by the handler rather than recalculating it, or by rate-limiting the number of actual page updates using setTimeout._ I was trying to play around with setTimeout but couldn't get anything :/ maybe someone else can? I guess this isn't really a performance issue though... – aug Jan 26 '13 at 16:20
  • 3
    I see this on Chrome 24, but not Firefox 18, IE 9 or Opera 11. – Guffa Jan 26 '13 at 16:21
  • 1
    I see this in Chrome 24 as well. @aug - how does that explain it ? – adeneo Jan 26 '13 at 16:22
  • There was a chromium bug report opened for this back in November: http://code.google.com/p/chromium/issues/detail?id=161464 – Ben McCormick Jan 26 '13 at 16:23
  • @adeneo I guess doesn't really explain but I was thinking their suggestion could have been useful maybe somehow delaying the mousemove so there's time to see if a click has been registered (even if it is a millisecond or so). – aug Jan 26 '13 at 16:24
  • 2
    For me, without moving the mouse (even not touching it), mousemove is fired hundreds time on chrome 24 windows 7. Seems like a tick fired it. Thats really a weird bug. – A. Wolff Jan 26 '13 at 16:46
  • 1
    There is a great deal of difference between Console panel in chrome and console in firebug. I have always had conflicting resulting in chrome console as compared with Firebug Console. – defau1t Jan 26 '13 at 16:59

7 Answers7

9

Mousemove appears to be binded to every mouse action there is in Chrome, so store the mouse position every time the mouse "moves" and check it against the previous mouse position to validate that it has indeed "moved"..

var currentPos=[];
$("div").on({
    mousemove: function(e) {
        if (e.pageX!==currentPos[0] && e.pageY !==currentPos[1]){
            currentPos=[e.pageX,e.pageY];
        this.innerHTML = "Event: " + e.type;
        console.log("move");
        }
    },
    click: function(e) {
        this.innerHTML = "Event: " + e.type;
        console.log("click");
    }
});

Demo | Source

extramaster
  • 2,635
  • 2
  • 23
  • 28
  • I guess you shouldn't mix `window.event` with `e` object. Otherwise, your solution also makes sense. – VisioN Jan 26 '13 at 16:48
  • The timeStamp hack didn't work for me but this one did. – Justin Jan 22 '15 at 21:14
  • This is a good solution, but won't work if a click event is adding a mouse move event listener to start a drag listening sequence. – dudewad Jan 17 '16 at 04:36
7

This appears to be a bug in Chrome that was first reported back in November, and remains open.

Chromium Issue 161464

If you are targeting Chrome specifically then it may be worth comparing the event timestamps to get around it (using some minimum delta time as @ExplosionPills suggested. But if you're looking for general behavior it seems that you're better off treating them as separate events, because in every browser but chrome (and maybe Safari? the bug is labeled as webkit-core) they will in fact be separate events.

Ben McCormick
  • 25,260
  • 12
  • 52
  • 71
3

This behavior is odd, and it doesn't seem to occur universally (happens in Chrome/IE for me, but not FFX). I think you haven't gotten a straight answer because there isn't one really.

It's possible that the mouse is moved very slightly by the click action, but that's probably not it. Could just be a browser quirk. These don't even seem to be the same event since stopImmediatePropagation in click doesn't stop mousemove from firing. If you focus the element and hit a keyboard button, it will actually trigger click and only click.

Since this is so quirky, it seems like the only way to deal with it is times. As much of a kludge as this is, I do notice that click happens one millisecond before mousemove, so you could get close by comparing the click timestamp + 2 (or 10):

mousemove: function(e) {
    if ($(this).data('lastClick') + 10 < e.timeStamp) {

http://jsfiddle.net/gKqVt/3/

This is very specific, though. You should consider not having behavior that occurs immediately on mousemove since it's so frequent.

Explosion Pills
  • 188,624
  • 52
  • 326
  • 405
  • +1 That's a good suggestion. In order to make `mousemove` event *work* from the start, you need to add the check for undefined data, e.g. http://jsfiddle.net/gKqVt/4/. – VisioN Jan 26 '13 at 16:32
  • @VisioN I didn't have a problem with that, but I agree that yours is more technically correct – Explosion Pills Jan 26 '13 at 16:34
  • The problem is that `undefined + 10 === NaN`, while `NaN < e.timeStamp` gives `false`, hence while there is no default value set, the `movemove` event won't be triggered. – VisioN Jan 26 '13 at 16:37
  • @VisioN - posted a fiddle 20 minutes ago that does this (almost) ?? – adeneo Jan 26 '13 at 16:37
  • @adeneo Didn't see your fiddle. That's a good alternative, you should post is as answer. – VisioN Jan 26 '13 at 16:40
  • My problem with this is that I need to set the threshold (10 in your case) so high that I start disregarding actual mousemove events in an attempt to avoid all the fraudulent ones. I've had to set it as high as 35-50 ms – Justin Jan 22 '15 at 20:31
  • in FF I find mousemove events fire when even just clicking – SuperUberDuper Nov 19 '15 at 10:18
  • I can confirm that in Chrome 69 on Windows 10, mousemove fires on the body and the document before a button's click handler fires. See https://codepen.io/MSCAU/pen/mzOBpX – MSC Oct 08 '18 at 07:49
3

Why don't just check that did the mouse really move or not like below:

function onMouseDown (e) {
    mouseDown = { x: e.clientX, y: e.clientY };
    console.log("click");
}

function onMouseMove (e) {
    //To check that did mouse really move or not
    if ( e.clientX !== mouseDown.x || e.clientY !== mouseDown.y) {
        console.log("move");
    }
}

FIDDLE DEMO

(I think it's will still correct in all browsers)

Ben Mack
  • 489
  • 2
  • 7
  • 29
0

var a,b,c,d;
  $(".prd img").on({
 mousedown: function(e){
   a= e.clientX, b= e.clientY;
 },
 mouseup: function(e){
   c= e.clientX, d= e.clientY;
   if(a==c&&b==d){
     console.log('clicked');
   }
 }
  });

Try this. This one work correct.

0

I noticed this behavior when I needed to differenciate between mousedown and mouseup without dragging between the two and mousedown and mouseup with dragging between them, the solution that I used is as follows:

var div = $('#clickablediv');
var mouseDown = false;
var isDragging = 0;
div.mousedown(function () {
   isDragging = false;
       mouseDown = true;
   }).mousemove(function () {
       if (mouseDown) isDragging++;
   }).mouseup(function () {
       mouseDown = false;
       var wasDragging = isDragging;
       isDragging = 0;
       if (!wasDragging || wasDragging<=1) {
           console.log('there was no dragging');
       }
   });

when I tried it, I noticed that periodacaly a simple click makes "isDragging" equal to 3 but not very frequently

Alexander Farber
  • 21,519
  • 75
  • 241
  • 416
AZNI HAMZA
  • 11
  • 1
0

I added the following to my mouseMove(event) function:

      function mouseMove(event)
      {
        if ((event.movementX == 0) && (event.movementY == 0)) return;

Not clear why it triggers when there is no movement, but this worked for me. Had the issue in Chrome 102.0.5005.61 at least. It did not happen a few years ago.

Dave Hubbard
  • 469
  • 5
  • 11