检测到浏览器没有鼠标,并且是仅触摸的
我正在开发一个非常不同的用于触摸的界面(当你点击时你的手指隐藏了屏幕)和鼠标(很大程度上依赖于hover预览)来开发一个web应用程序(而不是一个有趣的文本页面的网站)。 我怎么能检测到我的用户没有鼠标给他提供正确的界面? 我打算为鼠标和触摸(如一些笔记本电脑)的人留下一个开关。
浏览器中的触摸事件function实际上并不意味着用户正在使用触摸设备(例如,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);
(在适当的情况下listen
和unlisten
委托给addEventListener
或attachEvent
。)
希望这不会导致太多的可视化结果,如果你需要基于模式进行大规模的重新布局,这将是吸引人的。
主要的麻烦是你有以下不同类的设备/使用情况:
- 鼠标和键盘(桌面)
- 仅触摸(手机/平板电脑)
- 鼠标,键盘和触摸(触摸笔记本电脑)
- 触摸和键盘(平板电脑上的蓝牙键盘)
- 仅限鼠标(禁用用户/浏览首选项)
- 仅限键盘(禁用用户/浏览首选项)
- 触摸和鼠标(即从Galaxy Note 2笔盘旋事件)
更糟糕的是,人们可以从其中一些类别转换到其他类别(插入鼠标,连接到键盘),或者用户可能看到普通笔记本电脑上,直到触及屏幕。
假设浏览器中的事件构造函数的存在不是一个向前推进的好方法(并且有点不一致),那么你是正确的。 另外,除非你正在跟踪一个非常具体的事件,或者只是试图排除上面的几个类,否则使用事件本身并不是充分的证据。
例如,假设您已经发现用户发出了真正的鼠标移动(而不是触摸事件中的错误移动,请参阅http://www.html5rocks.com/en/mobile/touchandmouse/ )。
那又怎样?
您启用hover样式? 你添加更多的button?
无论哪种方式,你正在增加时间玻璃,因为你必须等待事件发生。
但是,当你的高贵的用户决定要拔掉他的鼠标,并全力以赴时,会发生什么事情呢?你是否等待他触摸你现在挤塞的界面,然后在他努力找出你现在拥挤的界面后立即改变它?
在子弹forms,引用灰泥在https://github.com/Modernizr/Modernizr/issues/869#issuecomment-15264101
- 我们想要检测鼠标的存在
- 在事件被解雇之前,Ae可能无法检测到
- 因此,我们正在检测的是在此会话中是否使用了鼠标 – 它不会立即从页面加载
- 我们可能也无法检测到没有鼠标 – 直到真正的时候它才会被定义(我认为这比将它设置为false更有意义,直到certificate为止)
- 而且我们可能无法检测鼠标在会话期间是否断开连接 – 与放弃鼠标的用户无法区分
一边:浏览器知道用户何时插入鼠标/连接到键盘,但不暴露给JavaScript ..当!
这应该引导你到以下几点:
跟踪给定用户的当前能力是复杂的,不可靠的,具有可疑的价值
虽然渐进式增强的想法在这里应用得非常好。 无论用户的情况如何,build立一个顺畅运作的体验。 然后根据浏览器特性/媒体查询进行假设,以在假定的上下文中添加相对的function。 鼠标的存在只是不同设备上的不同用户体验您的网站的众多方式之一。 在内核上创build一些有价值的东西,不要太担心人们点击button的方式。
@ Wyatt的回答非常好,给了我们很多想法。
在我的情况下,我select了听第一个互动,然后才设置一个行为。 所以,即使用户有一个鼠标,如果第一个交互是触摸,我会把它当作触摸设备。
考虑事件处理的顺序 :
- touchstart
- touchmove
- touchend
- 鼠标移到
- 鼠标移动
- 鼠标按下
- 鼠标松开
- 点击
我们可以假设,如果鼠标事件在触摸之前被触发,它是一个真正的鼠标事件,而不是一个模拟的事件。 示例(使用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); });
这对我有效
只能检测浏览器是否具有触摸function 。 没有办法知道它是否实际上有触摸屏或鼠标连接。
如果检测到触摸function,则可以通过监听触摸事件而不是鼠标事件来优先使用。
跨浏览器检测触摸function:
function hasTouch() { return (('ontouchstart' in window) || // html5 browsers (navigator.maxTouchPoints > 0) || // future IE (navigator.msMaxTouchPoints > 0)); // current IE10 }
然后可以用这个来检查:
if (!hasTouch()) alert('Sorry, need touch!);
或者select要听的事件:
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; }
(不能包含mouseup
或mousedown
因为这些事件也可以通过触摸来触发)
浏览器限制对底层系统API的访问,这需要能够检测诸如正在使用的系统的硬件function之类的function。
有可能写一个插件/扩展来访问这些,但通过JavaScript和DOM这种检测是有限的这个目的,人们将不得不编写一个特定于各种操作系统平台的插件。
所以最后:这种检测只能通过“好猜测”来估计。
既然你打算提供一种在界面之间切换的方法,那么简单地要求用户点击一个链接或一个button来“input”正确的应用程序版本是可行的吗? 那么你可以记住他们对未来访问的偏好。 这不是高科技,但它是100%可靠的:-)
当媒体查询级别4在浏览器中可用时,我们将能够使用“指针”和“hover”查询来使用鼠标检测设备。
如果我们真的想将这些信息传递给Javascript,我们可以使用CSS查询根据设备types设置特定的样式,然后在Javascript中使用getComputedStyle
来读取该样式,并从中派生出原始设备types。
但是,鼠标可以随时连接或拔出 ,用户可能想要在触摸和鼠标之间切换。 所以我们可能需要检测这个变化,并提供改变接口或自动这样做。
@SamuelRossille不幸的是,我不知道的浏览器暴露了鼠标的存在(或缺less)。
所以,就这样说,我们只需要尽我们所能,以我们现有的select…事件。 我知道这不是你正在寻找的东西…同意它目前是非常不理想的。
我们可以尽力弄清楚用户在任何时候是使用鼠标还是触摸。 这是一个使用jQuery和Knockout的快速而肮脏的例子:
//namespace window.ns = {}; // for starters, we'll briefly assume if touch exists, they are using it - default behavior ns.usingTouch = ko.observable(Modernizr.touch); //using Modernizr here for brevity. Substitute any touch detection method you desire // now, let's sort out the mouse ns.usingMouse = ko.computed(function () { //touch if (ns.usingTouch()) { //first, kill the base mousemove event //I really wish browsers would stop trying to handle this within touch events in the first place window.document.body.addEventListener('mousemove', function (e) { e.preventDefault(); e.stopImmediatePropagation(); }, true); //remove mouse class from body $('body').removeClass("mouse"); //switch off touch listener $(document).off(".ns-touch"); // switch on a mouse listener $(document).on('mousemove.ns-mouse', function (e) { if (Math.abs(window.lastX - e.clientX) > 0 || window.lastY !== e.clientY) { ns.usingTouch(false); //this will trigger re-evaluation of ns.usingMouse() and result in ns.usingMouse() === true } }); return false; } //mouse else { //add mouse class to body for styling $('body').addClass("mouse"); //switch off mouse listener $(document).off(".ns-mouse"); //switch on a touch listener $(document).on('touchstart.ns-touch', function () { ns.usingTouch(true) }); return true; } }); //tests: //ns.usingMouse() //$('body').hasClass('mouse');
您现在可以绑定/订阅usingMouse()和usingTouch()和/或使用body.mouse类定义界面。 只要检测到鼠标光标并在touchstart上,接口就会来回切换。
希望很快我们能从浏览器厂商那里得到一些更好的select。
你为什么不检测它是否有能力感知触摸和/或对鼠标移动作出反应?
// 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); }
Tera-WURFL可以通过将浏览器签名与其数据库进行比较来告诉您正在访问您的网站的设备的function。 给它一下,它的自由!
这在类似的情况下也适用于我。 基本上,假设用户没有鼠标,直到看到一连串的连续鼠标移动,而不介入mousedowns或mouseup。 不是很优雅,但它的作品。
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类的存在。
在我看来,这里不太痛苦的解决scheme是在启动时显示一个菜单(对于仅键盘用户使用'alt'pipe理),也可以用localStorage / cookies / serverside存储选项,否则保持下一个选项时间来访者。
看看modenizr的一个特点是触摸
http://modernizr.com/docs/#features-misc
虽然我没有完全testing它似乎工作得很好
这也是从modernizr页面链接http://www.html5rocks.com/en/mobile/touchandmouse/
正如其他人所指出的那样,明确地检测他们是否有鼠标是不可靠的。 这可以很容易地改变,取决于设备。 至less在文档尺度上,这绝对是一个你不能可靠地用布尔真或假的方法。
触摸事件和鼠标事件是独占的。 所以这可以有助于采取不同的行动。 问题是触摸事件更接近鼠标的上/下/移动事件,并且还触发点击事件。
从你的问题你说你想有一个hover预览。 除此之外,我不知道有关您的界面的任何其他细节。 我假设 ,由于缺less鼠标,您需要点按预览,而点击会执行不同的操作,因为hover预览。
如果是这种情况,你可以采取一些懒惰的方法来检测:
一个onclick事件总是会有一个带有鼠标的onmouseover事件。 所以请记下鼠标位于被点击的元素的顶部。
你可以用文档范围的onmousemove事件来做到这一点。 您可以使用event.target
来logging鼠标所在的元素。 然后,在您的onclick事件中,您可以检查鼠标是否实际上位于被单击的元素上(或元素的子元素)。
从那里你可以select依靠双方的点击事件,并根据结果采取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事件,就像你在这个iOS讨论中看到的那样,所以我们应该小心点。
基于触摸的浏览器只会在用户点击屏幕(用户的手指停止)时才会模拟此事件。 这意味着我们应该在mousemove处理程序中添加一个testing,以查看事件期间哪个鼠标button处于closures状态(如果有的话)。 如果没有鼠标button,我们可以安全地假设一个真实的鼠标存在。 如果鼠标按下,testing仍然没有结果。
那么这将如何实施呢? 这个问题表明,检查鼠标移动过程中哪个鼠标button被closures的最可靠的方法是实际侦听文档级别的3个事件:mousemove,mousedown和mouseup。 上下只会设置一个全局布尔标志。 此举将进行testing。 如果你有一个移动,布尔值是假的,我们可以假设一个鼠标存在。 查看问题的确切代码示例。
最后一点评论..这个testing是不理想的,因为它不能在加载时间执行。 因此,我会使用先前build议的渐进增强方法。 默认显示一个不支持鼠标指定hover界面的版本。 如果发现鼠标,使用JS在运行时启用此模式。 这应该尽可能无缝地显示给用户。
为了支持用户configuration的更改(即鼠标已断开连接),可以定期重新testing。 虽然我相信在这种情况下会更好地通知用户关于2种模式,并且让用户在它们之间手动切换(就像移动/桌面select总是可以颠倒的)。
在各种PC,Linux,iPhone,Android手机和标签上进行一些testing。 奇怪的是,没有简单的防弹解决scheme。 当一些有触摸,没有鼠标仍然存在触摸和鼠标事件的应用程序出现问题。 既然想要支持鼠标和只触摸的实例,想要同时处理,但是这会导致用户交互的两次发生。 如果可以知道设备上没有鼠标,那么可以知道忽略假冒/插入的鼠标事件。 尝试设置标志,如果遇到MouseMove,但一些浏览器抛出假MouseMove以及MouseUp和MouseDown。 试图检查时间戳,但认为这太冒险了。 底线:我发现创build假的鼠标事件的浏览器总是在插入的MouseDown之前插入一个MouseMove。 在99.99%的情况下,在具有真实鼠标的系统上运行时,有多个连续的MouseMove事件 – 至less有两个。 因此,logging系统是否遇到两个连续的MouseMove事件,并且如果从未满足此条件,则声明没有鼠标存在。 这可能太简单了,但它在我所有的testing设置上工作。 想想我会坚持下去,直到find更好的解决scheme。 吉姆
jQuery中的一个简单解决scheme,用于检测鼠标使用情况,从而解决了移动设备触发“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! });
当然,该设备仍然可以触摸和鼠标,但上述将保证一个真正的鼠标被使用。
刚刚find一个我觉得很优雅的解决scheme。
// 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 // ... } });
想推荐一个帮助我的脚本:
我已阅读并尝试了所有build议,没有足够的结果。
然后我再调查一下,发现这个代码 – device.js
我在客户的网站上使用这个来检测鼠标的存在:
( <html>
应该有desktop
类),看起来不错,对于touch
支持,我只是'ontouchend' in document
定期检查'ontouchend' in document
并使用来自两个检测的信息来承担我需要的特定事情。
我强烈build议不要这种方法。 考虑触摸屏,桌面大小的设备,而且还有一些不同的问题需要解决。
请使您的应用程序无需鼠标(即无hover预览)。
检测鼠标hoverfunction是否被支持而不是检测OS /浏览器types通常是一个更好的主意。 你可以简单地通过以下方法来实现:
if (element.mouseover) { //Supports the mouseover event }
请确保您不要执行以下操作:
if (element.mouseover()) { // Supports the mouseover event }
后者实际上会调用这个方法,而不是检查它的存在。
您可以在这里阅读更多信息: http : //www.quirksmode.org/js/support.html