使用JavaScript检测“触摸屏”设备的最佳方法是什么?

我写了一个jQuery插件,可以在桌面和移动设备上使用。 我想知道是否有JavaScript的方式来检测设备是否具有触摸屏function。 我正在使用jquery-mobile.js来检测触摸屏事件,它适用于iOS,Android等,但我也想根据用户的设备是否有触摸屏来编写条件语句。

那可能吗?

更新:在将一个特征检测库拉入项目之前,请阅读blmstr的回答 。 检测实际的触摸支持更为复杂,Modernizr只涵盖一个基本的用例。

Modernizr是一个伟大的,轻量级的方式来做任何网站上的各种function检测。

它只是将类添加到每个function的html元素。

然后,您可以在CSS和JS中轻松地定位这些function。 例如:

html.touch div { width: 480px; } html.no-touch div { width: auto; } 

和Javascript(jQuery示例):

 $('html.touch #popup').hide(); 

你有没有尝试过使用这个function? (这与Modernizr曾经使用过的一样。)

 function is_touch_device() { try { document.createEvent("TouchEvent"); return true; } catch (e) { return false; } } 

更新:

document.createEvent("TouchEvent")已经开始在最新的chrome中返回true (第17节)。 Modernizr刚刚更新了这个。 检查Modernizr在这里testing 。

更新你的function,使其工作:

 function is_touch_device() { return 'ontouchstart' in window; } 

更新:

我发现上面的IE10没有工作(在MS Surface上返回false)。 这是修复:

 function is_touch_device() { return 'ontouchstart' in window // works on most browsers || 'onmsgesturechange' in window; // works on IE10 with some false positives }; 

更新

在一些IE桌面版本'onmsgesturechange' in window将返回true,因此不可靠。 这稍微更可靠:

 function is_touch_device() { return 'ontouchstart' in window // works on most browsers || navigator.maxTouchPoints; // works on IE10/11 and Surface }; 

或Modernizr已经更新了他们的testing,以包括一些CSS媒体查询魔术,所以你可以尝试。

但是这些都还不够完美。 有关解释触摸检测问题的好文章,请参阅: Stu Cox:您无法检测到触摸屏

由于Modernizr在Windows Phone 8 / WinRT上没有检测到IE10,所以一个简单的,跨浏览器的解决scheme是:

 var supportsTouch = 'ontouchstart' in window || navigator.msMaxTouchPoints; 

你只需要检查一次,因为设备不会突然支持或不支持触摸,所以只需将其存储在一个variables中,以便更有效地使用它多次。

使用上面的所有注释,我已经组装了以下代码来满足我的需求:

 var isTouch = (('ontouchstart' in window) || (navigator.msMaxTouchPoints > 0)); 

我已经在iPad,Android(浏览器和Chrome),黑莓Playbook,iPhone 4s,Windows Phone 8,IE 10,IE 8,IE 10(带触摸屏的Windows 8),Opera,Chrome和Firefox进行了testing。

它目前在Windows Phone 7上失败,我还没有find该浏览器的解决scheme。

希望有人认为这有用。

我喜欢这一个:

 function isTouchDevice(){ return typeof window.ontouchstart !== 'undefined'; } alert(isTouchDevice()); 

如果您使用Modernizr ,那么使用前面提到的Modernizr.touch非常容易。

不过,我更喜欢使用Modernizr.touch和用户代理testing的组合,只是为了安全起见。

 var deviceAgent = navigator.userAgent.toLowerCase(); var isTouchDevice = Modernizr.touch || (deviceAgent.match(/(iphone|ipod|ipad)/) || deviceAgent.match(/(android)/) || deviceAgent.match(/(iemobile)/) || deviceAgent.match(/iphone/i) || deviceAgent.match(/ipad/i) || deviceAgent.match(/ipod/i) || deviceAgent.match(/blackberry/i) || deviceAgent.match(/bada/i)); if (isTouchDevice) { //Do something touchy } else { //Can't touch this } 

如果你不使用Modernizr,你可以简单地用('ontouchstart' in document.documentElement)replace上面的Modernizr.touch函数,

另请注意,testing用户代理iemobile将为您提供比Windows Phone更广泛的检测到的Microsoft移动设备。

也看到这个问题

我们尝试了modernizr的实现,但检测到触摸事件不再一致(IE 10在Windows桌面上有触摸事件,IE 11的作品,因为触发事件,并添加了指针API)。

所以我们决定优化网站作为触摸网站,只要我们不知道用户有什么inputtypes。 这比任何其他解决scheme更可靠。

我们的研究表明,大多数桌面用户在点击之前用鼠标在屏幕上移动,所以我们可以检测到他们,并改变他们的行为之前,他们可以点击或hover任何东西。

这是我们的代码的简化版本:

 var isTouch = true; window.addEventListener('mousemove', function mouseMoveDetector() { isTouch = false; window.removeEventListener('mousemove', mouseMoveDetector); }); 

工作小提琴

我已经这样做了,

 function isTouchDevice(){ return true == ("ontouchstart" in window || window.DocumentTouch && document instanceof DocumentTouch); } if(isTouchDevice()===true) { alert('Touch Device'); //your logic for touch device } else { alert('Not a Touch Device'); //your logic for non touch device } 

即使在Windows Surface平板电脑这个工作正常!

 function detectTouchSupport { msGesture = window.navigator && window.navigator.msPointerEnabled && window.MSGesture, touchSupport = (( "ontouchstart" in window ) || msGesture || window.DocumentTouch && document instanceof DocumentTouch); if(touchSupport) { $("html").addClass("ci_touch"); } else { $("html").addClass("ci_no_touch"); } } 

有一些比检查是否有touchScreen更好,是检查他们是否使用它,再加上这是更容易检查。

 if (window.addEventListener) { var once = false; window.addEventListener('touchstart', function(){ if (!once) { once = true; // Do what you need for touch-screens only } }); } 

我使用了上面的代码片段来检测是否触摸,所以我的fancybox iframe会显示在桌面电脑上,而不是触摸。 我注意到Opera Mini 4.0 for Android 4.0在单独使用blmstr代码时仍然注册为非触摸设备。 (有谁知道为什么?)

我结束了使用:

 <script> $(document).ready(function() { var ua = navigator.userAgent; function is_touch_device() { try { document.createEvent("TouchEvent"); return true; } catch (e) { return false; } } if ((is_touch_device()) || ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) || ua.match(/Android/)) { // Touch browser } else { // Lightbox code } }); </script> 

看看这个post ,它提供了一个非常好的代码片段,当触摸设备被检测到时该怎么做,或者如果调用touchstart事件该怎么做:

 $(function(){ if(window.Touch) { touch_detect.auto_detected(); } else { document.ontouchstart = touch_detect.surface; } }); // End loaded jQuery var touch_detect = { auto_detected: function(event){ /* add everything you want to do onLoad here (eg. activating hover controls) */ alert('this was auto detected'); activateTouchArea(); }, surface: function(event){ /* add everything you want to do ontouchstart here (eg. drag & drop) - you can fire this in both places */ alert('this was detected by touching'); activateTouchArea(); } }; // touch_detect function activateTouchArea(){ /* make sure our screen doesn't scroll when we move the "touchable area" */ var element = document.getElementById('element_id'); element.addEventListener("touchstart", touchStart, false); } function touchStart(event) { /* modularize preventing the default behavior so we can use it again */ event.preventDefault(); } 

我会避免使用屏幕宽度来确定设备是否是触摸设备。 有触摸屏大于699px,想到Windows 8. Navigatior.userAgent可能是很好的覆盖假的postives。

我会build议在Modernizr上检查这个问题 。

你想testing设备是否支持触摸事件或是触摸设备。 不幸的是,这不是一回事。

不,这是不可能的。 给出的优秀答案只是部分的,因为任何给定的方法都会产生假阳性和假阴性。 即使浏览器并不总是知道触摸屏是否存在,由于OS API,事实可以在浏览器会话期间改变,特别是在KVMtypes的安排下。

在这个优秀的文章中看到更多细节:

http://www.stucox.com/blog/you-cant-detect-a-touchscreen/

文章build议你重新考虑使你想要检测触摸屏的假设,他们可能是错的。 (我检查了我自己的应用程序,我的假设确实是错的!)

文章的结论是:

对于布局,假设每个人都有一个触摸屏。 鼠标用户可以使用大型UI控件,而不是触摸用户可以使用小型控件。 hover状态也是如此。

对于事件和交互,假定任何人都可以有触摸屏。 实现键盘,鼠标和触摸互动,确保没有互相阻挡。

尝试检测触摸的最大“陷阱”是在支持触摸和触控板/鼠标的混合设备上。 即使您能够正确检测到用户设备是否支持触摸,您真正需要做的是检测用户当前使用的input设备。 有一个详细的写这个挑战和一个可能的解决scheme在这里 。

基本上,确定用户是否刚刚触摸屏幕或使用鼠标/触控板的方法是在页面上注册touchstartmouseover事件:

 document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover" 

触摸动作将触发这两个事件,尽pipe前者( touchstart )总是在大多数设备上首先出现。 因此,依靠这种可预测的事件序列,您可以创build一种机制,dynamic地向文档根中添加或删除Can can-touch类,以反映当前文档中用户的当前inputtypes:

 ;(function(){    var isTouch = false //var to indicate current input type (is touch versus no touch)    var isTouchTimer    var curRootClass = '' //var indicating current document root class ("can-touch" or "")        function addtouchclass(e){        clearTimeout(isTouchTimer)        isTouch = true        if (curRootClass != 'can-touch'){ //add "can-touch' class if it's not already present            curRootClass = 'can-touch'            document.documentElement.classList.add(curRootClass)        }        isTouchTimer = setTimeout(function(){isTouch = false}, 500) //maintain "istouch" state for 500ms so removetouchclass doesn't get fired immediately following a touch event    }        function removetouchclass(e){        if (!isTouch && curRootClass == 'can-touch'){ //remove 'can-touch' class if not triggered by a touch event and class is present            isTouch = false            curRootClass = ''            document.documentElement.classList.remove('can-touch')        }    }        document.addEventListener('touchstart', addtouchclass, false) //this event only gets called when input type is touch    document.addEventListener('mouseover', removetouchclass, false) //this event gets called when input type is everything from touch to mouse/ trackpad })(); 

更多细节在这里 。

它看起来像Chrome 24现在支持触摸事件,可能为Windows 8.所以这里发布的代码不再有效。 而不是试图检测浏览器是否支持触摸,我现在绑定触摸和点击事件,并确保只有一个被调用:

 myCustomBind = function(controlName, callback) { $(controlName).bind('touchend click', function(e) { e.stopPropagation(); e.preventDefault(); callback.call(); }); }; 

然后调用它:

 myCustomBind('#mnuRealtime', function () { ... }); 

希望这可以帮助 !

我用:

 if(jQuery.support.touch){ alert('Touch enabled'); } 

在jQuery手机1.0.1

所有的浏览器支持,除了桌面的Firefox总是TRUE,因为Firefox的桌面支持响应devise的开发人员,即使你点击触摸button或不!

我希望Mozilla将在下一个版本中解决这个问题。

我使用的是Firefox 28桌面。

 function isTouch() { return !!("ontouchstart" in window) || !!(navigator.msMaxTouchPoints); } 

对于如何在Javascript中检测页面是否显示在触摸屏设备上的不同选项,我也遇到了很多困难。 国际海事组织,到目前为止,还没有真正的select来正确地检测选项。 浏览器要么报告桌面计算机上的触摸事件(因为操作系统可能是触摸式的),要么某些解决scheme在所有的移动设备上都不起作用。

最后,我意识到我从一开始就采取了错误的做法:如果我的页面在触摸和非触摸设备上看起来很相似,那么我可能根本不必担心检测属性:我的场景是去激活触摸设备上的button的工具提示,因为它们导致双击,我想单击一下来激活button。

我的解决scheme是重构视图,以便在button上不需要任何工具提示,并且最终我不需要从Javascript中检测具有缺点的方法的触摸设备。

您可以安装modernizer并使用简单的触摸事件。 这是非常有效的,并在我testing过的每个设备上都能正常工作,包括windows表面!

我创build了一个jsFiddle

 function isTouchDevice(){ if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){ alert("is touch"); return true; }else{ alert("is not touch"); return false; } } 

实际的答案似乎是考虑到上下文的问题:

1)公共网站 (不login)
编码UI以将两个选项一起使用。

2)login网站
捕获login表单上是否出现鼠标移动,并将其保存到隐藏的input中。 该值与login凭证一起传递,并添加到用户的会话中 ,因此可用于会话的持续时间。

jquery只能添加到login页面:

 $('#istouch').val(1); // <-- value will be submitted with login form if (window.addEventListener) { window.addEventListener('mousemove', function mouseMoveListener(){ // Update hidden input value to false, and stop listening $('#istouch').val(0); window.removeEventListener('mousemove', mouseMoveListener); }); } 

(+ 1到@Dave Burt和+1到@Martin Lantzsch在他们的答案)

jQuery v1.11.3

提供的答案中有很多很好的信息。 但是,最近我花了很多时间试图把所有的东西结合起来,成为一个可行的解决scheme来完成两件事情:

  1. 检测到正在使用的设备是触摸屏types的设备。
  2. 检测到该设备已被窃听。

除了这篇文章和使用Javascript检测触摸屏设备 ,我发现这个postPatrick Lauke非常有帮助: https ://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how /

这里是代码…

 $(document).ready(function() { //The page is "ready" and the document can be manipulated. if (('ontouchstart' in window) || (navigator.maxTouchPoints > 0) || (navigator.msMaxTouchPoints > 0)) { //If the device is a touch capable device, then... $(document).on("touchstart", "a", function() { //Do something on tap. }); } else { null; } }); 

重要! *.on( events [, selector ] [, data ], handler )方法需要有一个select器,通常是一个可以处理“touchstart”事件的元素,或者任何其他与触摸相关的事件。 在这种情况下,它是超链接元素“a”。

现在,您不需要处理JavaScript中常规的鼠标点击操作,因为您可以使用CSS来使用超链接“a”元素的select器来处理这些事件,如下所示:

 /* unvisited link */ a:link { } /* visited link */ a:visited { } /* mouse over link */ a:hover { } /* selected link */ a:active { } 

注:还有其他select器…

问题

由于使用触摸和鼠标input相结合的混合设备,您需要dynamic更改状态/variables,以控制用户是否是触摸用户时是否应该运行一段代码。

触摸设备也会触发mousemove

  1. 假设加载时触摸是错误的。
  2. 等到touchstart事件被触发,然后将其设置为true。
  3. 如果touchstart被触发,添加一个mousemove处理程序。
  4. 如果两个mousemove事件触发之间的时间小于10ms,则假定它们使用鼠标作为input。 删除事件,因为它不再需要,mousemove是一个昂贵的鼠标设备事件。
  5. 一旦touchstart被再次触发(用户返回使用触摸),variables被设置为true。 并重复这个过程,以dynamic的方式确定。 如果通过一些奇迹,mousemove会被荒谬地快速触发两次(在我的testing中几乎不可能在10ms内完成),下一个touchstart会将其设置为true。

在Safari iOS和Chrome上进行testing。

注意:MS Surface的指针事件不是100%确定的

Codepen演示


 const supportsTouch = 'ontouchstart' in window; let isUsingTouch = false; // `touchstart`, `pointerdown` const touchHandler = () => { isUsingTouch = true; document.addEventListener('mousemove', mousemoveHandler); }; // use a simple closure to store previous time as internal state const mousemoveHandler = (() => { let time; return () => { const now = performance.now(); if (now - time < 10) { isUsingTouch = false; document.removeEventListener('mousemove', mousemoveHandler); } time = now; } })(); // add listeners if (supportsTouch) { document.addEventListener('touchstart', touchHandler); } else if (navigator.maxTouchPoints > 0 || navigator.msMaxTouchPoints > 0) { document.addEventListener('pointerdown', touchHandler); } 
 var isTouchScreen = 'createTouch' in document; 

要么

 var isTouchScreen = 'createTouch' in document || screen.width <= 699 || ua.match(/(iPhone|iPod|iPad)/) || ua.match(/BlackBerry/) || ua.match(/Android/); 

我想是一个更彻底的检查。

扩展jQuery support对象:

 jQuery.support.touch = 'ontouchend' in document; 

现在你可以在任何地方查看,如下所示:

 if( jQuery.support.touch ) // do touch stuff 

其中的许多工作,但要么jQuery,或JavaScript的短信抱怨的语法。 考虑到你最初的问题要求一个“JavaScript”(而不是jQuery,而不是Modernizr)的方式来解决这个问题,下面是一个简单的函数,每次都有效。 这也是尽可能less的,你可以得到。

 function isTouchDevice() { return window.ontouchstart !== undefined; } console.log(isTouchDevice()); 

我会提到的最后一个好处是这个代码是框架和设备不可知的。 请享用!

目前为止,这似乎对我很好:

 //Checks if a touch screen is_touch_screen = 'ontouchstart' in document.documentElement; if (is_touch_screen) { // Do something if a touch screen } else { // Not a touch screen (ie desktop) } 

快速注意那些可能试图编写window.ontouchstart !== undefined – >请使用micnic answer,因为undefined不是JavaScript中的关键字。 大问题,如果开发写像这样的东西:

 undefined = window.ontouchstart; 

开发人员可以做任何他们想要的东西,你也可以检查是否window.ontouchstart = myNonExistingWord;

没有不尊重给这个答案的人:很确定我也是在我的代码中写的;)

当连接鼠标时,可以假设用户在页面准备就绪之后至less有一小段距离(相当于100%),而没有任何点击。 下面的机制检测到这一点。 如果检测到,我认为这是缺失触摸支持的标志,或者如果支持的话,在使用鼠标时不重要。 假设没有检测到触摸设备。

编辑这种方法可能不适合所有目的。 它可用于控制基于用户在加载页面上的交互而激活的function,例如图像查看器。 下面的代码也将鼠标事件绑定在没有鼠标的设备上。 其他方法可能会更好。

粗略地说,它是这样的(抱歉的jQuery,但类似的纯Javascript):

 var mousedown, first, second = false; var ticks = 10; $(document).on('mousemove', (function(e) { if(UI.mousechecked) return; if(!first) { first = e.pageX; return; } if(!second && ticks-- === 0) { second = e.pageX; $(document).off('mousemove'); // or bind it to somewhat else } if(first && second && first !== second && !mousedown){ // set whatever flags you want UI.hasmouse = true; UI.touch = false; UI.mousechecked = true; } return; })); $(document).one('mousedown', (function(e) { mousedown = true; return; })); $(document).one('mouseup', (function(e) { mousedown = false; return; })); 

您可以使用下面的代码:

 function isTouchDevice() { var el = document.createElement('div'); el.setAttribute('ongesturestart', 'return;'); // or try "ontouchstart" return typeof el.ongesturestart === "function"; } 

来源: 检测基于触摸的浏览和@mplungjan后 。

上述解决scheme基于没有浏览器嗅探文章的检测事件支持 。

您可以在下面的testing页面查看结果。

请注意,上面的代码只testing浏览器是否支持触摸,而不是设备。 所以如果你有触摸屏的笔记本电脑,你的浏览器可能不支持触摸事件。 最近的Chrome支持触摸事件 ,但其他浏览器可能不支持。

你也可以尝试:

 if (document.documentElement.ontouchmove) { // ... } 

但它可能无法在iPhone设备上工作。