检测到浏览器没有鼠标并且只能触摸

IT技术 javascript html css touch mouse
2021-01-18 13:54:49

我正在开发一个 web 应用程序(不是一个包含有趣文本页面的网站),它有一个非常不同的触摸界面(当你点击时你的手指会隐藏屏幕)和鼠标(严重依赖悬停预览)。如何检测我的用户没有鼠标来向他展示正确的界面?我打算为同时使用鼠标和触摸的人(如某些笔记本电脑)留下一个开关。

浏览器中的触摸事件功能实际上并不意味着用户正在使用触摸设备(例如,Modernizr 没有削减它)。如果设备有鼠标,正确回答问题的代码应该返回 false,否则返回 true。对于带有鼠标和触摸的设备,它应该返回 false(不仅仅是触摸)

附带说明一下,我的触摸界面可能也适用于仅使用键盘的设备,因此我希望检测的更多是缺少鼠标。

为了使需求更加明确,这是我希望实现的 API:

// Level 1


// The current answers provide a way to do that.
hasTouch();

// Returns true if a mouse is expected.
// Note: as explained by the OP, this is not !hasTouch()
// I don't think we have this in the answers already, that why I offer a bounty
hasMouse();

// Level 2 (I don't think it's possible, but maybe I'm wrong, so why not asking)

// callback is called when the result of "hasTouch()" changes.
listenHasTouchChanges(callback);

// callback is called when the result of "hasMouse()" changes.
listenHasMouseChanges(callback);
6个回答

主要的问题是您有以下不同类别的设备/用例:

  1. 鼠标和键盘(桌面)
  2. 仅触摸(手机/平板电脑)
  3. 鼠标、键盘和触控(触控笔记本电脑)
  4. 触摸和键盘(平板电脑上的蓝牙键盘)
  5. 仅鼠标(禁用用户/浏览偏好)
  6. 仅键盘(禁用用户/浏览偏好)
  7. 触摸和鼠标(即来自 Galaxy Note 2 笔的悬停事件)

更糟糕的是,人们可以从这些类中的一些过渡到其他类(插入鼠标,连接到键盘),或者用户可能看起来像在普通笔记本电脑上,直到他们伸手触摸屏幕。

您假设浏览器中存在事件构造函数不是前进的好方法(并且有些不一致),这是正确的。此外,除非您正在跟踪一个非常具体的事件或只是试图排除上述几个类,否则使用事件本身并不是充分的证据。

例如,假设您发现用户发出了真正的鼠标移动(不是来自触摸事件的虚假移动,请参阅http://www.html5rocks.com/en/mobile/touchandmouse/)。

然后呢?

你启用悬停样式?你添加更多按钮?

无论哪种方式,您都在增加玻璃的时间,因为您必须等待事件触发。

但是,当您的尊贵用户决定要拔掉他的鼠标并完全触摸时会发生什么..您是否等待他触摸您现在塞满的界面,然后在他努力查明您现在拥挤的用户界面后立即更改它?

以项目符号形式,在https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101引用 stucox

  • 我们想检测鼠标的存在
  • 在触发事件之前,Ae 可能无法检测到
  • 因此,我们正在检测的是,如果在此会话中使用了鼠标——它不会立即从页面加载
  • 我们可能也无法检测到没有鼠标——它在为真之前是未定义的(我认为这比在证明之前将其设置为假更有意义)
  • 而且我们可能无法检测到鼠标是否在会话期间断开连接——这与用户只是放弃鼠标无法区分

旁白:浏览器确实知道用户何时插入鼠标/连接到键盘,但不会将其暴露给 JavaScript .. dang!

这应该引导您到以下几点:

跟踪给定用户的当前能力是复杂的、不可靠的并且值得怀疑

不过,渐进增强的想法在这里非常适用。无论用户所处的环境如何,都能打造流畅运行的体验。然后根据浏览器功能/媒体查询进行假设,以添加在假设上下文中相对的功能。鼠标的存在只是不同设备上的不同用户体验您的网站的众多方式之一。在其核心创造一些有value的东西,不要太担心人们如何点击按钮。

很好的答案。希望用户总是有一个屏幕!我认为构建一个适合用户当前交互模式的界面是有意义的。在触摸笔记本电脑上,:hover当用户从鼠标切换到触摸时,调整应用程序(即元素和类似的东西)是有意义的用户当前似乎不太可能同时使用鼠标 + 触摸(我的意思是 comoonn 就像将 2 个鼠标连接到同一台计算机一样哈哈哈)
2021-03-15 13:54:49
@SebastienLorber -恨打破它给你,但用户并不一定总是有一个屏幕。是否可以使用 javascript 来检测屏幕阅读器是否正在用户机器上运行?
2021-04-02 13:54:49

截至 2018 年,有一种很好且可靠的方法来检测浏览器是否有鼠标(或类似的输入设备):CSS4 媒体交互功能现在几乎所有现代浏览器(IE 11 和特殊移动浏览器除外)都支持。

W3C:

指针媒体功能用于查询指针设备(如鼠标)的存在和准确性。

请参阅以下选项:

    /* The primary input mechanism of the device includes a 
pointing device of limited accuracy. */
    @media (pointer: coarse) { ... }

    /* The primary input mechanism of the device 
includes an accurate pointing device. */
    @media (pointer: fine) { ... }

    /* The primary input mechanism of the 
device does not include a pointing device. */
    @media (pointer: none) { ... }

    /* Primary input mechanism system can 
       hover over elements with ease */
    @media (hover: hover) { ... }

    /* Primary input mechanism cannot hover 
       at all or cannot conveniently hover 
       (e.g., many mobile devices emulate hovering
       when the user performs an inconvenient long tap), 
       or there is no primary pointing input mechanism */
    @media (hover: none) { ... }

    /* One or more available input mechanism(s) 
       can hover over elements with ease */
    @media (any-hover: hover) { ... }


    /* One or more available input mechanism(s) cannot 
       hover (or there are no pointing input mechanisms) */
    @media (any-hover: none) { ... }

媒体查询也可以在 JS 中使用:

if(window.matchMedia("(any-hover: none)").matches) {
    // do sth
}

有关的:

W3 文档:https : //www.w3.org/TR/mediaqueries-4/#mf-interaction

浏览器支持:https : //caniuse.com/#search=media%20features

类似问题:检测客户端设备是否支持 :hover 和 :focus 状态

我个人喜欢这个答案,但截至目前 (10/19),根据 caniuse.com,@media 悬停和指针 CSS 查询仅在全球约 85% 的设备上可用。当然也不错,95%以上最好。希望这将很快成为设备的标准。
2021-03-18 13:54:49
2020 年 9 月:我正在 Android 智能手机中尝试媒体匹配(悬停:悬停),它匹配,而在 w3 链接中说它不应该
2021-03-20 13:54:49
@MQuiggGeorgia 基本上我基本上同意你的批评,它还没有在所有地方都得到支持。caniuse.com 对我来说仍然支持 91.2% ( caniuse.com/#feat=css-media-interaction )。仔细看看,除了 IE 11 和移动设备上的特殊扁平化浏览器之外,它在任何地方都受支持。公平地说,这适用于任何现代功能,因为微软很久以前就停止实施 IE 功能。对于 IE 11,您可能会使用此处其他答案的后备。
2021-03-26 13:54:49
window.matchMedia("(any-pointer: fine)").matches由于某种原因,在我所有的移动浏览器和桌面上都返回 true。window.matchMedia("(any-hover: hover)").matches即使在没有鼠标的移动设备上,也总是返回 true。window.matchMedia("(any-pointer: coarse)").matches在移动设备上返回 true,在台式机上返回 false,但不考虑连接的鼠标或 s-pen。
2021-04-02 13:54:49
@raquelhortab 如果 W3 说它不应该比它不应该。你使用哪个浏览器?
2021-04-10 13:54:49

如何监听文档上的 mousemove 事件。然后,直到您听到该事件,您才假定该设备仅是触摸式或键盘式的。

var mouseDetected = false;
function onMouseMove(e) {
  unlisten('mousemove', onMouseMove, false);
  mouseDetected = true;
  // initializeMouseBehavior();
}
listen('mousemove', onMouseMove, false);

(在哪里listenunlisten委托给addEventListenerattachEvent酌情。)

希望这不会导致太多的视觉卡顿,如果您需要基于模式进行大量重新布局,那会很糟糕……

如果应用程序以初始屏幕和“继续”按钮启动,这可能会起作用。如果鼠标在第一个 mousedown 事件之前移动,那么您就有了鼠标。如果按钮直接加载在鼠标下方并且用户的手非常稳定(即使移动 1 个像素也应该被拾取),它才会失败。
2021-03-15 13:54:49
iPad 肯定会在 mousedown 事件之前触发 mousemove 事件。我发现 mousedown count > 0 和 mousedown count == mousemove count 是检测没有鼠标的好方法。我无法用真正的鼠标复制它。
2021-03-26 13:54:49
好主意,但在我们的测试中似乎不起作用iPad 触发此事件。
2021-04-02 13:54:49
@JeffAtwood 你最后在你的情况下做了什么?
2021-04-04 13:54:49
这是一个好主意,但不幸的是,当应用程序的 UI 取决于鼠标是否可用时,响应延迟将使其无法使用。鼠标移动到 iframe 本身上..
2021-04-09 13:54:49

@Wyatt 的回答很棒,给了我们很多思考。

就我而言,我选择监听第一次交互,然后才设置行为。因此,即使用户有鼠标,如果第一次交互是触摸,我也会将其视为触摸设备。

考虑到处理事件给定顺序

  1. 触摸启动
  2. 触摸移动
  3. 触端
  4. 鼠标移到
  5. 鼠标移动
  6. 鼠标按下
  7. 鼠标向上
  8. 点击

我们可以假设,如果鼠标事件在触摸之前被触发,则它是一个真正的鼠标事件,而不是模拟事件。示例(使用 jQuery):

$(document).ready(function() {
    var $body = $('body');
    var detectMouse = function(e){
        if (e.type === 'mousedown') {
            alert('Mouse interaction!');
        }
        else if (e.type === 'touchstart') {
            alert('Touch interaction!');
        }
        // remove event bindings, so it only runs once
        $body.off('mousedown touchstart', detectMouse);
    }
    // attach both events to body
    $body.on('mousedown touchstart', detectMouse);
});

那对我有用

对我不起作用,Ipad Safari (IOS8.3) 也使用此代码段检测到鼠标
2021-03-21 13:54:49
@netzaffin。感谢您的反馈,我发现使用 mousedown 而不是 mouseover 更一致。你能从你的 IOS 上看看这个小提琴,让我知道结果吗?干杯jsfiddle.net/bkwb0qen/15/embedded/result
2021-03-25 13:54:49
如果您有带鼠标的触摸屏,则只会检测最先使用的输入法。
2021-04-12 13:54:49

这是唯一可以检测,如果浏览器是触摸能力没有办法知道它是否真的连接了触摸屏或鼠标。

如果检测到触摸功能,则可以通过侦听触摸事件而不是鼠标事件来优先使用。

跨浏览器检测触摸功能:

function hasTouch() {
    return (('ontouchstart' in window) ||       // html5 browsers
            (navigator.maxTouchPoints > 0) ||   // future IE
            (navigator.msMaxTouchPoints > 0));  // current IE10
}

然后可以使用它来检查:

if (!hasTouch()) alert('Sorry, need touch!);

或选择要收听的事件,或者:

var eventName = hasTouch() ? 'touchend' : 'click';
someElement.addEventListener(eventName , handlerFunction, false);

或使用单独的方法进行触摸与非触摸:

if (hasTouch() === true) {
    someElement.addEventListener('touchend' , touchHandler, false);

} else {
    someElement.addEventListener('click' , mouseHandler, false);

}
function touchHandler(e) {
    /// stop event somehow
    e.stopPropagation();
    e.preventDefault();
    window.event.cancelBubble = true;
    // ...
    return false; // :-)
}
function mouseHandler(e) {
    // sorry, touch only - or - do something useful and non-restrictive for user
}

对于鼠标,只能检测鼠标是否正在使用,而不能检测它是否存在。可以设置一个全局标志来指示鼠标被使用检测到(类似于现有的答案,但稍微简化了一点):

var hasMouse = false;

window.onmousemove = function() {
    hasMouse = true;
}

(不能包含mouseupmousedown因为这些事件也可以通过触摸触发)

浏览器限制对低级系统 API 的访问,这些 API 需要能够检测正在使用它的系统的硬件功能等功能。

有可能编写一个插件/扩展来访问这些,但通过 JavaScript 和 DOM 这种检测仅限于此目的,并且必须为各种操作系统平台编写特定的插件。

所以总而言之:这种检测只能通过“好的猜测”来估计。