如何使用JavaScript最佳地检测“触屏”设备?

525

我编写了一个适用于桌面和移动设备的jQuery插件。我想知道是否有一种JavaScript方法可以检测设备是否具有触摸屏功能。我正在使用jquery-mobile.js来检测触摸屏事件,并且它在iOS、Android等设备上工作正常,但是我还想编写基于用户设备是否具有触摸屏的条件语句。

这种可能性存在吗?


这是更好的方法 var x = 'touchstart' in document.documentElement; console.log(x) // 如果支持,则返回true // 否则返回false - Risa__B
为什么即使有新技术出现,这个线程还是被保护了呢? - Andy Hoffman
38个回答

854

更新2021年

要查看旧答案:请查看历史记录。由于在帖子中保留历史记录时变得混乱,我决定从头开始。

我的原始答案说使用与Modernizr相同的函数可能是一个好主意,但现在已经无效了,因为他们在此PR上删除了“touchevents”测试:https://github.com/Modernizr/Modernizr/pull/2432,因为这是一个令人困惑的主题。

话虽如此,以下应该是一种相当不错的检测浏览器是否具有“触摸功能”的方法:

function isTouchDevice() {
  return (('ontouchstart' in window) ||
     (navigator.maxTouchPoints > 0) ||
     (navigator.msMaxTouchPoints > 0));
}

但是对于更高级的用例,比我聪明得多的人已经写了关于这个主题的文章,我建议阅读这些文章:


21
双重取反运算将一个值强制转换为布尔值,并强制函数返回truefalse。您可以在此处阅读更多信息:https://dev59.com/mm445IYBdhLWcg3w0dVD - Rob Flaherty
26
!! 这个双重否定符号是多余的,因为 in 操作符已经返回了一个布尔值。 - Steve
12
即使在非触摸设备(PC)上,“onmsgesturechange”也会评估为真。看起来window.navigator.msMaxTouchPoints更准确。在这里找到它 - Steve
6
即使我的屏幕没有触摸传感器,在Windows 8上的IE10上它仍会评估为真。我将我的旧笔记本电脑从Windows 7升级到了Windows 8。 - Pwner
2
此帖子的最新更新在IE10桌面版Windows上返回真值! - rorypicko
显示剩余17条评论

141

更新:在将整个特征检测库引入您的项目之前,请阅读下面的blmstr的答案。检测实际触摸支持更加复杂,而Modernizr仅涵盖基本用例。

Modernizr是一种非常棒、轻量级的方式,在任何站点上进行各种特性检测。

它简单地为每个特性向HTML元素添加类。

然后您可以在CSS和JS中轻松地针对这些特性进行定位。例如:

html.touch div {
    width: 480px;
}

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

并且 JavaScript(jQuery 示例):

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

95
Modernizr不会测试触摸屏,它会测试浏览器中触摸事件的存在性。请查看文档中的“Misc Tests”部分:http://www.modernizr.com/docs/#features-misc - Harry Love

135

自从交互媒体功能引入后,你只需要做:

if(window.matchMedia("(pointer: coarse)").matches) {
    // touchscreen
}

https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer

更新(由于评论):上述解决方案用于检测“粗指针” - 通常是触摸屏幕 - 是否为主要输入设备。如果你想检测是否有带有鼠标等的触摸屏幕设备,可以使用any-pointer: coarse代替。

欲了解更多信息,请参阅此处:Detecting that the browser has no mouse and is touch-only


16
这绝对是最好的解决方案,谢谢!尽管我建议仅针对主输入使用(pointer: coarse)。可以在生产中使用,因为很少有不支持此功能的浏览器仅限于桌面版。这里有一篇关于此主题的好文章在css-tricks上 - Fabian von Ellerts
2
同意这可能是最好的解决方案,因为它利用了浏览器本身具备的触摸检测机制。我正在使用它,显然它运行非常良好。 - Marcos Buarque

128

由于Modernizr无法检测Windows Phone 8/WinRT上的IE10,因此一个简单的跨浏览器解决方案是:

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

由于设备不会突然支持或不支持触摸功能,因此您只需要检查一次,然后将其存储在变量中,以便更高效地多次使用。


44

使用以上所有评论,我已经组装出了适合我的需求的以下代码:

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

我已在iPad、Android(浏览器和Chrome)、Blackberry Playbook、iPhone 4s、Windows Phone 8、IE 10、IE 8、IE 10(带Touchscreen的Windows 8)、Opera、Chrome和Firefox上进行了测试。

目前在Windows Phone 7上无法通过测试,我还没有找到该浏览器的解决方案。

希望有人会发现这个对他们有用。


你不能使用这个函数的原因是什么呢?function is_touch_device() { return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in navigator); }; - sidonaldson
使用该函数可以工作,但我通常喜欢使用上面的变量方法,这样它只被测试一次,并且在稍后检查代码时更快。此外,我发现需要测试msMaxTouchPoints是否大于0,因为没有触摸屏的Windows 8上的IE 10会返回0作为msMaxTouchPoints。 - David
1
在我的Windows 7上的Firefox 32上返回了“true”:( - vsync
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - David
'ontouchstart' in window true
在Ubuntu上的Firefox 51.0.1
- Ravi Gadhia

25

我喜欢这个:

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

alert(isTouchDevice());

14
不需要使用三元表达式来返回布尔值,只需使用表达式即可返回布尔值。 function isTouchDevice(){ return (window.ontouchstart !== undefined); } - Tim Vermaelen
1
你也可以使用以下代码:var isTouch = 'ontouchstart' in window;,但是这在最新的Chrome(v31)中不起作用,而var isTouch = 'createTouch' in window.document;仍然有效。 - Olivier
3
如先前接受的问题的评论中已经提到,“Modernizr不会测试触摸屏幕。它测试浏览器中触摸事件的存在”。你的函数在技术上应该是hasTouchEvents()而不是isTouchDevice()。 - hexalys
请注意,仅测试 touchstart 的相似方法将无法识别 Surface 作为触摸设备,因为IE使用 pointer 事件代替。 - CookieEater
该函数在Windows 8.1桌面电脑(无触摸屏)上的FF 27.0.1中返回TRUE。 - Nis
1
也许 @Nis 是对的,但在 Firefox 39 中,它会正确地返回 false。 - Dan Dascalescu

20
如果你使用 Modernizr,如前所述使用 Modernizr.touch 非常容易。
然而,我更喜欢结合使用 Modernizr.touch 和用户代理测试,以确保安全。
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,你可以简单地将上面的Modernizr.touch函数替换为('ontouchstart' in document.documentElement)
另外,请注意测试用户代理iemobile将比Windows Phone检测到更广泛的Microsoft移动设备。 此外,请参见这个SO问题

12
“do something touchy” 可以翻译为“做一些敏感的事情”,而“can't touch this”可以翻译为“无法触及这个”。 - Lee Saxon

16

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

因此,我们决定将网站优化为触摸站点,只要我们不知道用户的输入类型。这比任何其他解决方案更可靠。

我们的研究表明,大多数桌面用户会用鼠标在屏幕上移动,然后再单击,因此我们可以检测到他们并在他们能够单击或悬停任何内容之前更改行为。

以下是我们代码的简化版本:

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

13

检查设备是否具有触摸屏之外,还有一件更好的事情是检查设备是否正在使用它,而且这更容易检查。

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

9

演示代码

我是这样实现的;

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
}

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