iPad/iPhone hover problem causes the user to double click a link

后端 未结 26 1575
太阳男子
太阳男子 2020-11-27 09:18

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 inst

相关标签:
26条回答
  • 2020-11-27 09:36

    I "think" that your links have no onmouseover event, where 1 tap activates onmouseover and the double tap activates the link. but idk. I don't have an iPad. I think ya gotta use gesture/touch events.

    https://developer.apple.com/documentation/webkitjs

    0 讨论(0)
  • 2020-11-27 09:39

    I just found out that it works if you add an empty listener, don't ask me why, but I tested it on iPhone and iPad with iOS 9.3.2 and it worked fine.

    if(/iPad|iPhone|iPod/.test(navigator.userAgent) && !window.MSStream){
        var elements = document.getElementsByTagName('a');
        for(var i = 0; i < elements.length; i++){
            elements[i].addEventListener('touchend',function(){});
        }
    }
    
    0 讨论(0)
  • 2020-11-27 09:40

    cduruk's solution was quite effective, but caused problems on a few parts of my site. Because I was already using jQuery to add the CSS hover class, the easiest solution was to simply not add the CSS hover class on mobile devices (or more precisely, to ONLY add it when NOT on a mobile device).

    Here was the general idea:

    var device = navigator.userAgent.toLowerCase();
    var ios = device.match(/(iphone|ipod|ipad)/);
    
    if (!(ios)) {
        $(".portfolio-style").hover(
            function(){
                $(this).stop().animate({opacity: 1}, 100);
                $(this).addClass("portfolio-red-text");
            },
            function(){
                $(this).stop().animate({opacity: 0.85}, 100);
                $(this).removeClass("portfolio-red-text");
            }
        );
    }
    

    *code reduced for illustrative purposes

    0 讨论(0)
  • 2020-11-27 09:40

    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.

    0 讨论(0)
  • 2020-11-27 09:44

    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.

    0 讨论(0)
  • 2020-11-27 09:44

    You can use click touchend ,

    example:

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

    Above example will affect all links on touch devices.

    If you want to target only specific links, you can do this by setting a class on them, ie:

    HTML:

    <a href="example.html" class="prevent-extra-click">Prevent extra click on touch device</a>

    Jquery:

    $('a.prevent-extra-click').on('click touchend', function() {
        var linkToAffect = $(this);
        var linkToAffectHref = linkToAffect.attr('href');
        window.location = linkToAffectHref;
    });
    

    Cheers,

    Jeroen

    0 讨论(0)
提交回复
热议问题