watusi / jquery-mobile-iscrollview

JQuery Mobile widget plug-in for easy use of the iScroll javascript scroller.
408 stars 183 forks source link

What's the best way to handle scrolling on clickable elements? #111

Closed nathanathan closed 11 years ago

nathanathan commented 11 years ago

When scrolling on clickable elements I'll often inadvertently trigger their click/tap events. The solution I'm using right now is to use the jQm vmouseup and vmousedown events instead of tap and only trigger my code if the screenX and screenY event properties don't change much between the down and up events. Is there a cleaner way to do this?

nathanathan commented 11 years ago

Update: I've found I can avoid creating a bunch of special handlers for checking mouse deltas by creating one vmousup handler that triggers vmousecancel events on all targets if they are greater than some threshold distance from the last vmousedown event.

TLDR: If you include this snippet in your code you can go on using tap events as you would otherwise and they will not be triggered when you scroll.

var lastDownEvt;
$(document).on("vmousedown", function(evt) {
  lastDownEvt = evt;
});
$(document).on("vmouseup vmouseout", function (evt){
  var thresh = 12;
  if(!lastDownEvt) return;
  if(evt.target !== lastDownEvt.target) return;
  if(Math.abs(evt.screenX - lastDownEvt.screenX) > thresh ||
     Math.abs(evt.screenY - lastDownEvt.screenY) > thresh) {
      $(lastDownEvt.target).trigger("vmousecancel");
  }
});
jtara commented 11 years ago
  1. There's no good reason to ever use tap events, IMO, because it is implemented only on touch devices. vmousedown is a better choice, because it is a synthetic merger of both tap and mousedown and will work on any device.
  2. I think it's impractical to use either tap or vmousedown within a scroller. It's a logical impossibility. The user has to touch the screen in order to start scrolling. If you are using this to perform some action when the user touches the item, it is almost always acceptable (and usually preferable) to use either click or (for better performance on some touch devices) vclick. This will trigger when the user lifts their finger, and so there is no conflict with scrolling.
  3. There should be no false triggering of either click or vclick. I use both of these all the time without any special gyrations like the above.

I'm closing this for now. If you can provide a specific example that can be tested, I will re-open it.

nathanathan commented 11 years ago

To see an example of the issue, try mouse scrolling in Chrome on the iscrollview demo page. Whenever you scroll on an item you will end up opening its page.

  1. jQm tap handlers also handle clicks in Chrome and presumably other browsers. I haven't used vclick and after reading the documentation on it I can't tell what it does differently from tap.
  2. In all the testing I've done taps are triggered on/after vmouseup.
  3. I've tested clicks/vclicks, they both have the same accidental triggering when scrolling issue.
nathanathan commented 11 years ago

One more thing I've noticed is that jQuery Mobile has some code that should does what I'm proposing when the page is scrolled (look for where the moveDistanceThreshold constant is used). However, the jQm code doesn't work with iscrollviews because it looks at the event pageX/Y rather than its screenX/Y.