iPad/iPhone悬停问题导致用户需要双击链接。

132
我以前建的一些网站使用了jquery鼠标事件......我刚刚买了一个iPad,发现所有的鼠标悬停事件都被转换为点击事件...所以例如我需要做两个点击而不是一个...(先是悬停,然后才是实际点击)
是否有一种解决方法可以解决这个问题?也许有一个我应该使用而不是mouseover/out等的jquery命令.. 谢谢!

1
你的事件绑定在什么上面?例如,onclick事件应该能正常工作... onmouseover、onmouseout和CSS的:hover是有点难处理的,因为触摸屏没有"hover"可用。你有代码示例吗? - scunliffe
我建议您重新思考界面设计(如果可能的话)。iPad / iPhone上的交互方式与PC上不完全相同,因此最好让您的网站感觉像是针对iPad / iPhone / 其他具有类似多点触控机制的触摸设备编写的。这只是一个想法。 - jer
我同意“jer”的观点。这是一个奇怪的问题,我个人认为解决方案不是“变通”。我认为将桌面浏览器上的“鼠标悬停”翻译成触摸屏浏览器上的“手指轻触”是有道理的。如果您同意这种翻译,但想要一次轻触而不是两次,则可能需要对iPad事件(例如“touchstart”)进行功能检测并更改事件处理程序。也许将代码提取到一个jquery插件中,“触摸或点击”类似的功能根据特性以不同的方式触发,但在我看来似乎是针对您的网站/应用程序的。 - Andy Atkinson
1
我认为这种翻译实际上是一种功能。如果您设置了悬停事件,那么肯定有一些实用性可见。单击会显示悬停元素,第二次点击会跟随链接“后面”的悬停。 - Aaron
27个回答

0

受到MacFreak的启发,我组合了一些适合我的东西。

这个js方法可以防止在ipad上悬停,并且可以防止在某些情况下将点击注册为两次点击。在CSS中,如果您的css中有任何:hover伪类,请将它们更改为.hover。例如,.some-class:hover变为.some-class.hover

在ipad上测试此代码,以查看css和js悬停方法在行为上的不同(仅在悬停效果中)。 CSS按钮没有花哨的点击警报。 http://jsfiddle.net/bensontrent/ctgr6stm/

function clicker(id, doStuff) {
  id.on('touchstart', function(e) {
    id.addClass('hover');
  }).on('touchmove', function(e) {
    id.removeClass('hover');
  }).mouseenter(function(e) {
    id.addClass('hover');
  }).mouseleave(function(e) {
    id.removeClass('hover');
  }).click(function(e) {
    id.removeClass('hover');
    //It's clicked. Do Something
    doStuff(id);
  });
}

function doStuff(id) {
  //Do Stuff
  $('#clicked-alert').fadeIn(function() {
    $(this).fadeOut();
  });
}
clicker($('#unique-id'), doStuff);
button {
  display: block;
  margin: 20px;
  padding: 10px;
  -webkit-appearance: none;
  touch-action: manipulation;
}
.hover {
  background: yellow;
}
.btn:active {
  background: red;
}
.cssonly:hover {
  background: yellow;
}
.cssonly:active {
  background: red;
}
#clicked-alert {
  display: none;
}
<button id="unique-id" class="btn">JS Hover for Mobile devices<span id="clicked-alert"> Clicked</span>

</button>
<button class="cssonly">CSS Only Button</button>
<br>This js method prevents hover from sticking on an ipad, and prevents the click registering as two clicks. In CSS, if you have any :hover in your css, change them to .hover For example .some-class:hover to .some-class.hover


0

当你有jQuery UI下拉菜单时,这对我很有效

if (navigator.userAgent.match(/(iPod|iPhone|iPad)/)) {
      $('.ui-autocomplete').off('menufocus hover mouseover');
}

0
感谢MacFreek的回答,我想出了这个解决方案。当我发现有时会连续出现两个mousemove事件而不触发click事件时,它变得更加先进了。

double mousemove

(function () {
    //https://dev59.com/u3A75IYBdhLWcg3w9-Ox#42162450
    function isIosSafari() {
        var ua = (window.navigator && navigator.userAgent) || '';
        var iOS = !!ua.match(/iPad/i) || !!ua.match(/iPhone/i);
        var webkit = !!ua.match(/WebKit/i);
        var iOSSafari = iOS && webkit && !ua.match(/CriOS/i);
        return iOSSafari;
    }
    (function removeHoverIosSafari() {
        if (!isIosSafari()) return;

        // Tags of interest
        function shouldPrevent(target) {
            var tagName = target.tagName.toLowerCase();
            var datasetBind = target.dataset.bind;
            var preventFilter = (datasetBind && datasetBind.indexOf('click') > -1) || (tagName == 'a' || tagName == 'button');
            return preventFilter;
        }
        var eventSelector = {
            touchend: function (_, target) {
                // Reset on touchend
                target.dataset._clicked_ = '';
                target.dataset._mousemove_ = '0';
                target.dataset._timeOutId_ = '';
            },
            mouseover: function (e) {
                e.preventDefault();
            },
            mousemove: function (e, target) {
                e.preventDefault();

                var _mousemoves = +(target.dataset._mousemove_ || '0');
                _mousemoves = _mousemoves + 1;
                console.log('mousemoves: ' + _mousemoves);
                target.dataset._mousemove_ = _mousemoves;
                if (_mousemoves > 1 && !target.dataset._timeOutId_) {
                    var id = setTimeout(function () {
                        console.log('double mousemove click fired');
                        target.click();
                    }, 80); // 80ms worked for me, could probably be lower
                    target.dataset._timeOutId_ = id;
                }
            },
            click: function (e, target) {
                if (target.dataset._clicked_) {
                    console.log('prevented doubleclick');
                    e.preventDefault();
                    return;
                }
                // prevent timeout click
                if (target.dataset._timeOutId_) {
                    console.log('cleared timeout');
                    clearTimeout(+target.dataset._timeOutId_);
                }
                // mark element as clicked
                target.dataset._clicked_ = 'true';
            }
        }
        function preventHover(e) {
            var target = e.target;
            //There is no point in continuing if the item for unknown reasons doesnt't have a clickFunction, tagName or dataset (DOMStringMap)
            if (!(target && target.click && target.tagName && target.dataset)) return;
            if (!shouldPrevent(target)) return;
            var type = e.type;
            console.log(type, target);
            eventSelector[type] && eventSelector[type](e, target);
        }

        document.addEventListener('touchend', preventHover, true);
        document.addEventListener('mouseover', preventHover, true);
        document.addEventListener('mousemove', preventHover, true);
        document.addEventListener('click', preventHover, true);
    })();
})();

0
避免在hover css事件中更改"display"样式。我在hover状态下有"display: block"。删除后,iOS可以通过单击进行链接。顺便说一句,最新的iOS更新似乎修复了这个“功能”。

0

解决iPad双击问题的最简单方法是将CSS悬停效果包装在媒体查询@media (pointer: fine)中:

@media (pointer: fine) {
  a span {
    display: none;
  }
  a:hover span {
    display: inline-block;
  }
}

这个媒体查询包含的CSS只会应用于桌面端。

这个解决方案的说明在这里 https://css-tricks.com/annoying-mobile-double-tap-link-issue/


-1
你可以像这样检查 navigator.userAgent
if(!navigator.userAgent.match(/iPhone/i) || !navigator.userAgent.match(/iPad/i)) {
    //bind your mouseovers...
}

但是您需要检查黑莓、Droid、其他触摸屏设备。如果userAgent包含Mozilla、IE、Webkit或Opera,也可以仅绑定鼠标悬停事件,但仍需对某些设备进行筛选,因为例如Droid会将其userAgent字符串报告为:

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

iPhone的字符串类似。如果你只是筛选iPhone、iPod、iPad、Android和Blackberry,你可能会得到大多数手持设备,但不是所有的。


我想,为了不要让自己变得疯狂,现在最好的做法可能就是编写一个跳过悬停事件的脚本。所以我想第一个答案是正确的...而且你说得对...我应该考虑到所有其他设备...我希望Jquery或某个插件拥有这种检测功能..! - Francesco
http://wurfl.sourceforge.net/ 这可能是你的答案。这是一个无线设备数据库。不像 jQuery 插件那样直接,但你可以自己编写一个!还有 http://www.tera-wurfl.com/,它使用数据库而不是 XML 文件。我没有深入研究过,但可能有托管版本,这样你就不必担心保持 wurfl 文件或 tera-wurfl 数据库的最新状态了。 - jasongetsdown
1
我是否遗漏了什么,还是问题并不是关于检测iPad,而是关于在iPad上解决特定行为的问题? - Andrew Hedges

-2

只需创建一个CSS媒体查询,排除平板电脑和移动设备,并将悬停效果放在其中。您不需要使用jQuery或JavaScript来实现此功能。

@media screen and (min-device-width:1024px) {
    your-element:hover {
        /* Do whatever here */
    }
}

请确保将此代码添加到您的HTML头部,以确保它使用实际像素而不是分辨率进行计算。

<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=no" />

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接