如何检测浏览器是否支持鼠标悬停事件?

14
假设我有一个网页,其中有一些onmouseover的javascript行为来下拉菜单(或类似的东西)。
显然,在iPad或智能手机等触摸设备上无法正常工作。
如何检测浏览器是否支持悬停事件,例如onmouseover或onmouseout以及CSS中的:hover伪标签?
注意:我知道如果我担心这个问题,我应该用不同的方式编写它,但我想知道是否可以进行检测。
编辑:当我说“支持悬停事件”时,我真正意思是“浏览器是否有悬停事件的有意义表示”。如果硬件支持但软件不支持(反之亦然),则没有有意义的表示。除了一些即将推出的技术,我认为没有任何触摸设备具有悬停事件的有意义表示

我认为你的问题需要重新表述,因为理论上iPad支持onhover,但输入方式使其不可能。所以你的问题应该是:如何检测用户是否具有悬停在项目上的硬件能力? - orlp
也许这可以为你提供一个开始:https://dev59.com/F2865IYBdhLWcg3wHK7u - amosrivera
@nightcracker - 从网站(和我)的角度来看,硬件是否支持悬停并不重要 - 唯一重要的是是否有有意义的onmouseover或onmouseout钩子。我会在问题中澄清。 - Damovisa
@amosriviera - 感谢你的回复,这个问题中有一些有趣的内容。有一个答案给了我一个iPad的选项,但没有跨浏览器的选择。 - Damovisa
5个回答

18

这种方法可以兼容更多的设备和浏览器。

try {
   document.createEvent("TouchEvent");
   alert(true);
}
catch (e) {
   alert(false);
}

阅读更多


2
我在我测试的安卓设备上根本无法让被接受的答案起作用,但这个可以很好地工作。 - drobert
1
被接受的答案对我也没有用,但是这个解决了问题!谢谢,Johan。 - Greg Pettit
2
最新版本的Chrome(v.32,Win7,无触摸屏)存在误报。 - raykendo

11
var supportsTouch = (typeof Touch == "object");

只需检测是否为触摸设备,然后执行您的特殊操作即可。 这是最简单的方法,因为大多数触摸设备模拟鼠标事件,但没有以鼠标为驱动的设备模拟触摸事件。

更新:考虑到现在有多少设备以及Johan的评论,我建议简单地使用Modernizr


2
这适用于所有/大多数触摸设备吗?包括安卓手机和平板电脑、诺基亚触摸屏以及苹果设备? - Damovisa
Android和iThings支持率达到99.9%,Symbian?从某个QtWebKit版本开始支持,但不要问我是哪个Symbian版本。 - Thomas
你正在寻找替代方案吗?考虑使用onmousemove,但这将需要超时和其他操作,并且可能会在某些平台上被模拟。 - Thomas
3
需要注意的是,支持触摸事件的设备并不一定无法支持悬停功能:它们可能支持多种交互方式(例如笔)。 - user234932
尽管Surface是一个触摸设备,但Surface平板电脑上的IE10和11不支持触摸事件。 - sbaechler
如果设备支持触摸,则仅在有实际意义的情况下提供悬停行为会使该设备变得更加无用,因为依赖于触摸功能的用户仍然不能使用悬停。因此,在我看来,检测触摸是一种有效的方法。 - user234932

10

现在已经是2016年了,很多设备既有触摸屏,又有类似于鼠标的输入方式。不能触摸并不是判断能否使用“鼠标悬停”功能的好方法。以下是一些例子:

  • “主动笔”数字化设备(如 Galaxy Note 手机和平板电脑(Android)、Microsoft Surface (Windows)和 Wacom Cintiq(Mac/Windows/Android)),我认为 iPad Pro 也是一样的,其中笔就像鼠标一样工作,当距离屏幕约1厘米时可以“空中悬停”
  • 带有触摸屏和传统笔记本电脑触控板等的 Windows 笔记本电脑/混合设备
  • 可以连接到任何计算机并与鼠标一起使用的触摸屏监视器

因此,用户可能一分钟内无法使用悬停,然后,在同一设备上,在不刷新页面的情况下,他们从 Galaxy Note 中拿出笔(假设它不会着火),突然间他们正在使用悬停进行交互,并且他们期望它可以正常工作。


如果您需要知道用户能否使用并且当前正在使用方便的“鼠标悬停”设备,您可以:

  • mousemove 事件绑定到文档 body 上,如果触发鼠标移动的光标正在移动,则激活“具有悬停”状态(例如,在 body 上添加一个类user-can-mouseover),然后立即解除绑定,以便它只会发生一次。
  • 还要绑定一个 touchstart 事件来暂时停用那个 mousemove,并在 touchend 上重新激活它,以便在触摸上触发鼠标事件的浏览器上(在 Android 和 Windows 上非常普遍),正常的触摸滚动不会触发 mousemove
  • 使用mousemove事件解绑这些touchstarttouchend事件以进行良好的管理。
  • 这将导致“可以悬停”状态在用户开始使用类似鼠标的输入设备时触发。


    例如,使用混合设备:

    1. 最初,用户使用触摸和滑动浏览网页。
    2. 他们打开您的应用程序,在理解了它是什么后使用触摸上下滑动。到目前为止,“可以悬停”的条件不可用。
    3. 他们决定这是那种需要比他们的粗手指更精确的情况,因此他们拿出数字笔或拿起鼠标。
    4. 这会导致光标在页面上移动,而未结束的触摸事件已经发生,因此触发了您的“可以悬停”条件。

    ...并且对于老式的桌面工作站,使用鼠标:

    1. 页面加载。
    2. 用户在做任何事情时移动鼠标,立即触发鼠标移动事件。
    3. 立即触发“可以悬停”状态。

    5

    非传统浏览器的另一种方法是利用媒体查询hoverany-hover

    matchMedia('(hover: hover)').matches; // Primary device can hover
    
    matchMedia('(hover: none)').matches; // Primary device cannot hover
    
    matchMedia('(any-hover: hover)').matches; // At least one of the connected devices can hover
    
    matchMedia('(any-hover: none)').matches; // None of the connected devices can hover
    

    很棒的答案。我刚刚在三星Galaxy Note 8上尝试了一下,链接的“hover”示例与笔(悬停时为黄色)完美配合,但“any-hover”则没有反应(悬停时没有任何变化)。奇怪的是,因为笔是触摸之后的次要输入方式,所以我本来期望它会相反呢? - user56reinstatemonica8

    3

    根据user568458的回答,提供了一组功能,允许你在触摸设备上启用/禁用:hover样式(我还没有在所有设备上进行尝试):

    function detectMouseMove() {
        $(document).one('mousemove', function() { 
            $('body').addClass('hoverActive');
            detectTouchEvent();
        });
    }
    function detectTouchEvent() {
        $(document).one('touchstart', function() { 
            $('body').removeClass('hoverActive');
            detectMouseMove();
        });
    }
    

    然后您可以在样式表中使用.hoverActive,在任何:hover选择器之前,以防止移动浏览器尝试显示悬停状态。


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