Using mousedown event on mobile without jQuery mobile?

Esaevian picture Esaevian · Jun 21, 2012 · Viewed 61.6k times · Source

I've built a webapp, and for a little bit of polish, I wanted to add mousedown and mouseup handlers to swap out images (in this case, to make a button look like it's being pressed).

my code is something like this:

window.onload = function() {
    //preload mouse down image here via Image()
    $("#button_img").mousedown(function(){$("#button_img").attr("src","button_on.png");});
    $("#button_img").mouseup(function(){$("#button_img").attr("src","button_off.png")});
}

This works swimmingly on the desktop, but on mobile (testing in iOS Safari), the mousedown and mouseup events happen at the same time, so effectively nothing happens.

I tried to use the vmousedown and vmouseup events in jQueryMobile, however this code:

//include jquerymobile.js and jquerymobile.css 
window.onload = function() {
    //preload mouse down image here via Image()
    $("#button_img").vmousedown(function(){$("#button_img").attr("src","button_on.png");});
    $("#button_img").vmouseup(function(){$("#button_img").attr("src","button_off.png")});
}

Just gave me the errors that vmousedown and vmouseup don't exist. Also, jQueryMobile overrides the CSS I've already written for the page.

So is there a way to get vmousedown and vmouseup to work, and to do so without jQuery Mobile's CSS?

Answer

Jasper picture Jasper · Jun 21, 2012

You're looking for touchstart and touchend. They are the events that vmousedown and vmouseup attempt to mimic.

Here's an example:

window.onload = function() {
    //preload mouse down image here via Image()
    $("#button_img").bind('touchstart', function(){
        $("#button_img").attr("src","button_on.png");
    }).bind('touchend', function(){
        $("#button_img").attr("src","button_off.png");
    });
}

This will work without any framework on any device that supports touch events. You could use something like Modernizr to do this test and if the device does not support touch events, bind to the regular desktop events.

When you use touchstart/touchend/touchmove you get some interesting information, for instance how many touches are occurring at once, so you can detect if the user is scrolling or attempting to zoom.

UPDATE

Since the event object inside an event handler differs for touch events and mouse events, if you want to know the coordinates of the event either way, you can do something like this (the example below assumes Modernizr has been loaded):

//determine which events to use
var startEventType = 'mousedown',
    endEventType   = 'mouseup';

if (Modernizr.touch === true) {
    startEventType = 'touchstart';
    endEventType   = 'touchend';
}

//bind to determined event(s)
$("#button_img").bind(startEventType, function(event) {

    //determine where to look for pageX by the event type
    var pageX = (startEventType === 'mousedown')
                ? event.pageX
                : event.originalEvent.touches[0].pageX;

    ...
})...

UPDATE

I was looking this over and it seems like you don't need to detect the event type before binding the event handler:

//bind to determined event(s)
$("#button_img").bind('mousedown touchstart', function(event) {

    //determine where to look for pageX by the event type
    var pageX = (event.type.toLowerCase() === 'mousedown')
                ? event.pageX
                : event.originalEvent.touches[0].pageX;

    ...
})...

If you are worried about receiving both events in quick succession you could use a timeout to throttle the event handler:

//create timer
var timer = null;

//bind to determined event(s)
$("#button_img").bind('mousedown touchstart', function(event) {

    //clear timer
    clearTimeout(timer);

    //set timer
    timer = setTimeout(function () {

        //determine where to look for pageX by the event type
        var pageX = (event.type.toLowerCase() === 'mousedown')
                    ? event.pageX
                    : event.originalEvent.touches[0].pageX;

        ...

    }, 50);
})...

Note: You can force mousedown and touchstart events in quick succession with developer tools but I'm not sure about the real world use case here.