iPad/iPhone hover problem causes the user to doubl

2020-01-24 18:41发布

I have some websites I built times ago, that use jquery mouse events...I just got an ipad and i noticed that all the mouse over events are translated in clicks...so for instance i have to do two clicks instead of one..(the first hover, than the actual click)

is there a workaround ready to solve this? maybe a jquery command i shoudl have used instead of mouseover/out etc.. thanks!

25条回答
爱情/是我丢掉的垃圾
2楼-- · 2020-01-24 19:07

I am too late, I know but this is one of the easiest workaround I've found:

    $('body').on('touchstart','*',function(){   //listen to touch
        var jQueryElement=$(this);  
        var element = jQueryElement.get(0); // find tapped HTML element
        if(!element.click){
            var eventObj = document.createEvent('MouseEvents');
            eventObj.initEvent('click',true,true);
            element.dispatchEvent(eventObj);
        }
    });

This does not only works for links(anchor tags) but for other elements also. Hope this helps.

查看更多
孤傲高冷的网名
3楼-- · 2020-01-24 19:10

I had the following problems with the existing solutions, and found something that seems to solve all of them. This assumes you're aiming for something cross browser, cross device, and don't want device sniffing.

The problems this solves

Using just touchstart or touchend:

  • Causes the event to fire when people are trying to scroll past the content and just happened to have their finger over this element when they starting swiping - triggering the action unexpectedly.
  • May cause the event to fire on longpress, similar to right click on desktop. For example, if your click event goes to URL X, and the user longpresses to open X in a new tab, the user will be confused to find X open in both tabs. On some browsers (e.g. iPhone) it may even prevent the long press menu from appearing.

Triggering mouseover events on touchstart and mouseout on touchmove has less serious consequences, but does interfere with the usual browser behaviour, for example:

  • A long press would trigger a mouseover that never ends.
  • Many Android browsers treat the location of the finger on touchstart like a mouseover, which is mouseouted on the next touchstart. One way to see mouseover content in Android is therefore to touch the area of interest and wiggle your finger, scrolling the page slightly. Treating touchmove as mouseout breaks this.

The solution

In theory, you could just add a flag with touchmove, but iPhones trigger touchmove even if there's no movement. In theory, you could just compare the touchstart and touchend event pageX and pageY but on iPhones, there's no touchend pageX or pageY.

So unfortunately to cover all bases it does end up a little more complicated.

$el.on('touchstart', function(e){
    $el.data('tstartE', e);
    if(event.originalEvent.targetTouches){
        // store values, not reference, since touch obj will change
        var touch = e.originalEvent.targetTouches[0];
        $el.data('tstartT',{ clientX: touch.clientX, clientY: touch.clientY } );
    }
});
$el.on('touchmove', function(e){
    if(event.originalEvent.targetTouches){
        $el.data('tstartM', event.originalEvent.targetTouches[0]);
    }
});

$el.on('click touchend', function(e){
    var oldE = $el.data('tstartE');
    if( oldE && oldE.timeStamp + 1000 < e.timeStamp ) {
        $el.data('tstartE',false);
        return;
    }
    if( $el.data('iosTouchM') && $el.data('tstartT') ){
        var start = $el.data('tstartT'), end = $el.data('tstartM');
        if( start.clientX != end.clientX || start.clientY != end.clientY ){
            $el.data('tstartT', false);
            $el.data('tstartM', false);
            $el.data('tstartE',false);
            return;
        }
    }
    $el.data('tstartE',false);

In theory, there are ways to get the exact time used for a longpress instead of just using 1000 as an approximation, but in practice it's not that simple and it's best to use a reasonable proxy.

查看更多
祖国的老花朵
4楼-- · 2020-01-24 19:13

You could check navigator.userAgent like this:

if(!navigator.userAgent.match(/iPhone/i) || !navigator.userAgent.match(/iPad/i)) {
    //bind your mouseovers...
}

but you would have to check for blackberries, droids, umpty other touchscreen devices. You could also bind the mouseovers only if the userAgent contains Mozilla, IE, Webkit, or Opera, but you still need to screen for some devices because the Droid, for instance, reports its userAgent string as:

Mozilla/5.0 (Linux; U; Android 2.0.1; en-us; Droid Build/ESD56) AppleWebKit/530.17 (KHTML, like Gecko) Version/4.0 Mobile Safari/530.17

The iPhone's string is similar. If you just screen for iPhone, iPod, iPad, Android and Blackberry you might get the majority of handhelds, but not all of them.

查看更多
Juvenile、少年°
5楼-- · 2020-01-24 19:15

To get the links working without breaking touch scrolling, I solved this with jQuery Mobile's "tap" event:

    $('a').not('nav.navbar a').on("tap", function () {
        var link = $(this).attr('href');
        if (typeof link !== 'undefined') {
            window.location = link;
        }
    });
查看更多
Luminary・发光体
6楼-- · 2020-01-24 19:16

Haven't tested this fully but since iOS fires touch events, this could work, assuming you are in a jQuery setting.

$('a').on('click touchend', function(e) {
    var el = $(this);
    var link = el.attr('href');
    window.location = link;
});

The idea is that Mobile WebKit fires a touchend event at the end of a tap so we listen for that and then redirect the browser as soon as a touchend event has been fired on a link.

查看更多
干净又极端
7楼-- · 2020-01-24 19:16

MacFreak's answer was extremely helpful to me. Here's some hands-on code in case it helps you.

PROBLEM - applying touchend means every time you scroll your finger over an element, it responds as if you've pressed it, even if you were just trying to scroll past.

I'm creating an effect with jQuery which fades up a line under some buttons to "highlight" the hovered button. I do not want this to mean you have to press the button twice on touch devices to follow the link.

Here are the buttons:

<a class="menu_button" href="#">
    <div class="menu_underline"></div>
</a>

I want the "menu_underline" div to fade up on mouseover and fade out on mouseout. BUT I want touch devices to be able to follow the link on one single click, not two.

SOLUTION - Here's the jQuery to make it work:

//Mouse Enter
$('.menu_button').bind('touchstart mouseenter', function(){
    $(this).find(".menu_underline").fadeIn();
});

//Mouse Out   
$('.menu_button').bind('mouseleave touchmove click', function(){
    $(this).find(".menu_underline").fadeOut();
});

Many thanks for your help on this MacFreak.

查看更多
登录 后发表回答