检测到浏览器没有鼠标且仅触摸

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了检测到浏览器没有鼠标且仅触摸相关的知识,希望对你有一定的参考价值。

我正在开发一个webapp(不是一个有趣文本页面的网站),它有一个非常不同的触摸界面(当你点击时你的手指隐藏了屏幕)和鼠标(严重依赖于悬停预览)。如何检测到我的用户没有鼠标向他显示正确的界面?我计划为鼠标和触摸的人留下一个开关(就像一些笔记本电脑)。

浏览器中的触摸事件功能实际上并不意味着用户正在使用触摸设备(例如,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);
答案

如何在文档上监听mousemove事件。然后,直到您听到该事件,您才认为该设备仅为触摸或键盘。

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

listenunlisten酌情委托给addEventListenerattachEvent。)

希望这不会导致太多的视觉冲击,如果您需要基于模式的大量重新布局,它会很糟糕...

另一答案

你为什么不检测它是否有能力感知触摸和/或对鼠标移动作出反应?

// This will also return false on
// touch-enabled browsers like Chrome
function has_touch() {
  return !!('ontouchstart' in window);
}

function has_mouse() {
  return !!('onmousemove' in window);
}
另一答案

在类似的情况下,这对我有用。基本上,假设用户没有鼠标,直到您看到一系列连续的鼠标移动,而不会干预mousedowns或mouseups。不是很优雅,但它的工作原理。

var mousedown = false;
var mousemovecount = 0;
function onMouseDown(e){
    mousemovecount = 0;
    mousedown = true;
}
function onMouseUp(e){
    mousedown = false;
    mousemovecount = 0;
}
function onMouseMove(e) {
    if(!mousedown) {
        mousemovecount++;
        if(mousemovecount > 5){
            window.removeEventListener('mousemove', onMouseMove, false);
            console.log("mouse moved");
            $('body').addClass('has-mouse');
        }
    } else {
        mousemovecount = 0;
    }
}
window.addEventListener('mousemove', onMouseMove, false);
window.addEventListener('mousedown', onMouseDown, false);
window.addEventListener('mouseup', onMouseUp, false);
另一答案

我在这里看到的主要问题是,大多数触摸设备都会触发鼠标事件以及相应的触摸设备(touchstart - > mousedown,touchmove - > mousemove等)。对于仅键盘的键盘,最后用于现代键盘,它们具有通用浏览器,因此您甚至无法检测到MouseEvent类的存在。

在我看来,这里不那么痛苦的解决方案是在启动时显示一个菜单(仅对键盘用户进行'alt'管理),并可能将选项存储在localStorage / cookies / serverside中,或者保留下一个salme选项。访客来的时间。

另一答案

看看modenizr的一个功能就是触控

http://modernizr.com/docs/#features-misc

虽然我没有完全测试,但似乎工作得很好

这也是现代化页面http://www.html5rocks.com/en/mobile/touchandmouse/的链接

另一答案

正如其他人所指出的那样,明确地检测他们是否有鼠标是不可靠的。这可以很容易地改变,具体取决于设备。这绝对是你无法使用布尔值true或false来可靠的,至少在文档范围内。

触摸事件和鼠标事件是独占的。所以这有助于采取不同的行动。问题是触摸事件更接近鼠标上/下/移动事件,并且还触发点击事件。

从你的问题,你说你想要悬停预览。除此之外,我不知道有关您的界面的任何其他细节。我假设没有鼠标你需要点击预览,而点击会因为悬停预览而执行不同的操作。

如果是这种情况,你可以采取一些懒惰的方法来检测:

onclick事件将始终带有带鼠标的onmouseover事件。因此请注意鼠标位于已单击的元素的顶部。

您可以使用文档范围的onmousemove事件执行此操作。您可以使用event.target记录鼠标所在的元素。然后在您的onclick事件中,您可以检查鼠标是否实际位于被单击的元素上(或元素的子元素)。

从那里,您可以选择依赖于两者的click事件,并根据结果采取A或B动作。如果某些触摸设备不发出点击事件(而您必须依赖ontouch *事件),则B动作可能无效。

另一答案

我不认为识别仅触摸设备是可能的(据我所知)。主要问题是触摸设备也触发了所有鼠标和键盘事件。请参阅以下示例,两个警报对于触摸设备都返回true。

function is_touch_present() {
  return ('ontouchstart' in window) || ('onmsgesturechange' in window);
}

function is_mouse_present() {
  return (('onmousedown' in window) && ('onmouseup' in window) && ('onmousemove' in window) && ('onclick' in window) && ('ondblclick' in window) && ('onmousemove' in window) && ('onmouseover' in window) && ('onmouseout' in window) && ('oncontextmenu' in window));
}

alert("Touch Present: " + is_touch_present());
alert("Mouse Present: " + is_mouse_present());
另一答案

在我看来,最好的想法是mousemove听众(目前是最佳答案)。我相信这种方法需要稍微调整一下。确实,基于触摸的浏览器甚至可以模拟mousemove事件,正如你在this iOS discussion中看到的那样,所以我们应该小心一点。

有意义的是,当用户点击屏幕(用户的手指向下)时,基于触摸的浏览器将仅模拟此事件。这意味着我们应该在mousemove处理程序中添加一个测试,以查看事件期间哪个鼠标按钮关闭(如果有)。如果没有鼠标按钮关闭,我们可以安全地假设存在真正的鼠标。如果鼠标按钮关闭,则测试仍然不确定。

那么如何实现呢?这个question表明在鼠标移动期间检查哪个鼠标按钮关闭的最可靠方法是实际监听文档级别中的3个事件:mousemove,mousedown和mouseup。向上和向下只会设置一个全局布尔标志。此举将进行测试。如果你有一个移动并且布尔值为假,我们可以假设存在一个鼠标。查看确切代码示例的问题。

最后一条评论..此测试并不理想,因为它无法在加载时执行。因此,我会使用先前建议的渐进增强方法。默认情况下显示不支持鼠标特定悬停界面的版本。如果发现鼠标,请使用JS在运行时启用此模式。这应该尽可能无缝地呈现给用户。

为了支持用户配置的更改(即鼠标已断开连接),您可以定期重新测试。虽然我相信在这种情况下更好地通知用户有关这两种模式并允许用户在它们之间手动切换(很像移动/桌面选择,总是可以颠倒)。

另一答案

在各种PC,Linux,iPhone,android手机和标签上进行一些测试。很奇怪,没有简单的防弹解决方案。当一些具有Touch且没有鼠标的人仍然将Touch和Mouse事件呈现给应用程序时出现问题。由于确实要支持仅鼠标和仅触摸实例,因此希望同时处理这两个实例,但这会导致用户交互的两次出现。如果可以知道设备上没有鼠标,则可以知道忽略伪造/插入的鼠标事件。如果遇到MouseMove,尝试设置标志,但有些浏览器抛出假的MouseMove以及MouseUp和MouseDown。试过检查时间戳,但认为这太冒险了。结论:我发现创建假鼠标事件的浏览器总是在插入的MouseDown之前插入一个MouseMove。在99.99%的情况下,当在具有真实鼠标的系统上运行时,有多个连续的MouseMove事件 - 至少两个。因此,跟踪系统是否遇到两个连续的MouseMove事件,并声明如果从未满足此条件,则不存在鼠标。这可能太简单了,但是我的所有测试设置都在工作。我想我会坚持下去,直到找到更好的解决方案。 - 吉姆W

另一答案

jQuery中用于检测鼠标使用情况的简单解决方案,解决了移动设备也触发“mousemove”事件的问题。只需添加一个touchstart监听器即可删除mousemove监听器,以便在触摸时不会触发它。

$('body').one('touchstart.test', function(e) {
  // Remove the mousemove listener for touch devices
  $('body').off('mousemove.test');
}).one('mousemove.test', function(e) {
  // MOUSE!
});

当然,该设备仍然可以触摸和鼠标,但上述将保证使用真正的鼠标。

另一答案

刚刚找到了一个我认为非常优雅的解决方案。

// flag as mouse interaction by default
var isMouse = true;

// detect a touch event start and flag it
$(window).on('touchstart', function () {
  // if triggers touchstart, toggle flag
  // since touch events come before mouse event / click
  // callback of mouse event will get in callback
  // `isMouse === false`
  isMouse = false;
});

// now the code that you want to write
// should also work with `mouse*` events
$('a.someClass').on('click', function () {
  if (isMouse) {
    // interaction with mouse event
    // ...
  } else {
    // reset for the next event detection
    // this is crucial for devices that have both
    // touch screen and mouse
    isMouse = true;

    // interaction with touch event
    // ...
  }
});
另一答案

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

  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 ..当然!

这应该会引导您进行以下操作:

跟踪给定用户的当前能力是复杂的,不可靠的,并且具有可疑的优点

但是,渐进式增强的想法在这里很适用。无论用户的上下文如何,都可以构建一种平稳运行的体验。然后根据浏览器功能/媒体查询进行假设,以添加在假定上下文中相对的功能。鼠标的存在只是不同设备上不同用户体验您的网站的众多方式之一。在内核中创建具有优点的东西,不要过于担心人们如何点击按钮。