Is there a way to TouchEndInside in Mobile Safari?

2019-04-14 08:51发布

问题:

I'm trying to determine whether a users does a touchupinside in mobile safari for an iPhone web app. So far I've been unsuccessful. touchend event fires regardless of where the touchup event happens on the screen, and I can't seem to discern that the target has changed by anything in the event argument.

Can anyone point me in the right direction on how to capture a touchendinside (vs. touchendoutside) event using javascript?

$('a.arrow').bind('touchend',function(e) {
        console.log($(e.srcElement)); //both of these always return the same element
        console.log($(e.toElement)); //both of these always return the same element
    });

回答1:

I found an article Google published indicating how to detect whether a touchend is inside versus outside. The basic trick is:

  • Have 3 handlers: one on touchstart, touchmove, and touchend.
    1. touchstart: Save the (x,y) coordinates of the touch
    2. touchmove: Check that the touch hasn't moved a certain number of pixels on either axis, and if so, stop tracking the touch.
    3. touchend: If you are still tracking it, it is "inside"; if not, it is "outside".

You can always get more complex by using the actual target's bounds, etc., but for most applications that is probably sufficient.



回答2:

@Chris R. Donnelly is spot on. You need to use a combination of the three js events ( touchstart, touchmove and touchend) to effectively build your own gesture recogniser.

The Google approach is probably a really good way to go. I have not tried it yet.

Here's a basic example of a "touch up inside" listener for Mobile Safari that only listens for js-events on the target element. It will ignore any touch that originates outside the element, any touch that ends outside the element, and any touch that is dragged inside the element. This does not handle clicks (you should add that if you're supporting desktop too).

<script type="text/javascript">
  document.getElementById("yourElementId").addEventListener('touchstart', touchstart, false);
  document.getElementById("yourElementId").addEventListener('touchmove', touchmove, false);
  document.getElementById("yourElementId").addEventListener('touchend', touchend, false);
  var touchStartCoord = null;
  function touchstart (e) {
    touchStartCoord = {x: e.touches[0].pageX, y: e.touches[0].pageY};
    return true;
  };
  function touchmove (e) {
    if (touchStartCoord != null)
    {
      var tolerance = 10.0;
      if (Math.abs(e.touches[0].pageX-touchStartCoord.x) > tolerance || Math.abs(e.touches[0].pageY-touchStartCoord.y) > tolerance)
      {
        // moved too far, cancels event for this touch
        touchStartCoord = null;
      }
    }
    return true;
  };
  function touchend (e) {
    if (touchStartCoord != null)
    {
      window.location.href = "http://geospike.com/";
      return true;
    }
  };
</script>

If you want to support multiple elements, you could wrap it up in a reusable way.