Update: Please read blmstr's answer below before pulling a whole feature detection library into your project. Detecting actual touch support is more complex, and Modernizr only covers a basic use case.
document.createEvent("TouchEvent") 已经开始在最新的chrome(第17节)中返回 true . Modernizr不久前更新了这个 . Check Modernizr test out here .
像这样更新你的功能,使其工作:
function is_touch_device() {
return 'ontouchstart' in window;
}
UPDATE 2
我发现以上不适用于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
};
UPDATE 3
'onmsgesturechange' in window 将在某些IE桌面版本中返回true,因此不可靠 . 这可以稍微更可靠地工作:
function is_touch_device() {
return 'ontouchstart' in window // works on most browsers
|| navigator.maxTouchPoints; // works on IE10/11 and Surface
};
UPDATE 2018
时间流逝,有新的更好的方法来测试这个 . 我基本上提取并简化了Modernizr的检查方式:
function is_touch_device() {
var prefixes = ' -webkit- -moz- -o- -ms- '.split(' ');
var mq = function(query) {
return window.matchMedia(query).matches;
}
if (('ontouchstart' in window) || window.DocumentTouch && document instanceof DocumentTouch) {
return true;
}
// include the 'heartz' as a way to have a non matching MQ to help terminate the join
// https://git.io/vznFH
var query = ['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join('');
return mq(query);
}
var isTouch = true;
window.addEventListener('mousemove', function mouseMoveDetector() {
isTouch = false;
window.removeEventListener('mousemove', mouseMoveDetector);
});
2
有什么比检查他们是否有触摸屏更好,是检查他们是否使用它,加上更容易检查 .
if (window.addEventListener) {
var once = false;
window.addEventListener('touchstart', function(){
if (!once) {
once = true;
// Do what you need for touch-screens only
}
});
}
3
Working Fiddle
我这样做了;
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
}
尝试检测触摸的最大"gotcha"是支持触摸和触控板/鼠标的混合设备 . 即使你're able to correctly detect whether the user' s设备支持触摸,您真正需要做的是检测用户当前使用的输入设备 . 有一个详细的写这个挑战和a possible solution here .
document.addEventListener('touchstart', functionref, false) // on user tap, "touchstart" fires first
document.addEventListener('mouseover', functionref, false) // followed by mouse event, ie: "mouseover"
触摸操作将触发这两个事件,尽管前者( touchstart )总是在大多数设备上首先出现 . 因此,依靠这个可预测的事件序列,您可以创建一种机制,动态地向文档根添加或删除 can-touch 类,以反映此时文档上用户的 current 输入类型:
;(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
})();
$(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();
}
function isTouchDevice(){
if(Modernizr.hasEvent('touchstart') || navigator.userAgent.search(/Touch/i) != -1){
alert("is touch");
return true;
}else{
alert("is not touch");
return false;
}
}
4
实际答案似乎是考虑上下文的答案:
1) Public site (无登录) 对UI进行编码以同时使用这两个选项 .
2) Login site 捕获登录表单上是否发生鼠标移动,并将其保存为隐藏状态输入 . 该值与登录凭据一起传递并添加到用户的 session ,因此可以在会话期间使用 .
Jquery仅添加到登录页面:
$('#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);
});
}
$(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;
}
});
function isTouchDevice() {
return !!window.ontouchstart;
}
console.log(isTouchDevice());
我要提到的最后一个好处是这个代码是框架和设备无关的 . 请享用!
4
范围jQuery support 对象:
jQuery.support.touch = 'ontouchend' in document;
现在你可以在任何地方查看它,如下所示:
if( jQuery.support.touch )
// do touch stuff
9
到目前为止,这似乎对我来说还不错:
//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 (i.e. desktop)
}
30 回答
由于Modernizr在Windows Phone 8 / WinRT上没有检测到IE10,因此一个简单的跨浏览器解决方案是:
您只需要检查一次,因为设备不会突然支持或不支持触摸,因此只需将其存储在变量中,这样您就可以更有效地使用它多次 .
使用上面的所有评论,我汇总了以下代码,以满足我的需求:
我在iPad,Android(浏览器和Chrome),Blackberry Playbook,iPhone 4s,Windows Phone 8,IE 10,IE 8,IE 10(带触摸屏的Windows 8),Opera,Chrome和Firefox上进行了测试 .
它目前在Windows Phone 7上失败,但我还没有找到该浏览器的解决方案 .
希望有人觉得这很有用 .
I like this one:
我会避免使用屏幕宽度来确定设备是否是触摸设备 . 有触摸屏远大于699px,想想Windows 8. Navigatior.userAgent可能很好地覆盖虚假的postives .
我建议在Modernizr上查看this issue .
您是否想要测试设备是否支持触摸事件或是否为触摸设备 . 不幸的是,这不是一回事 .
Update: Please read blmstr's answer below before pulling a whole feature detection library into your project. Detecting actual touch support is more complex, and Modernizr only covers a basic use case.
Modernizr是一种在任何网站上进行各种功能检测的轻巧方式 .
它只是为每个功能的html元素添加类 .
然后,您可以在CSS和JS中轻松地定位这些功能 . 例如:
和Javascript(jQuery示例):
你尝试过使用这个功能吗? (这与Modernizr过去常用的相同 . )
UPDATE 1
document.createEvent("TouchEvent")
已经开始在最新的chrome(第17节)中返回true
. Modernizr不久前更新了这个 . Check Modernizr test out here .像这样更新你的功能,使其工作:
UPDATE 2
我发现以上不适用于IE10(在MS Surface上返回false) . 这是修复:
UPDATE 3
'onmsgesturechange' in window
将在某些IE桌面版本中返回true,因此不可靠 . 这可以稍微更可靠地工作:UPDATE 2018
时间流逝,有新的更好的方法来测试这个 . 我基本上提取并简化了Modernizr的检查方式:
在这里,他们使用的是非标准的
touch-enabled
媒体查询功能,我认为这有点奇怪和不好的做法 . 但是,嘿,在现实世界中,我猜它有效 . 在将来(当所有人都支持它们时),这些媒体查询功能可以为您提供相同的结果:pointer
和hover
.看看source of how Modernizr are doing it .
有关解释触摸检测问题的好文章,请参阅:Stu Cox: You Can't Detect a Touchscreen .
如果您使用Modernizr,则很容易使用前面提到的
Modernizr.touch
.但是,为了安全起见,我更喜欢使用
Modernizr.touch
和用户代理测试的组合 .如果你不使用Modernizr,你可以简单地用
('ontouchstart' in document.documentElement)
替换上面的Modernizr.touch
函数另请注意,测试用户代理
iemobile
将为您提供比Windows Phone
更广泛的检测到的Microsoft移动设备 .Also see this SO question
我们尝试了modernizr实现,但检测到触摸事件不再一致(IE 10在Windows桌面上有触摸事件,IE 11可以工作,因为已经删除了触摸事件并添加了指针api) .
因此,只要我们不知道用户的输入类型,我们就决定将网站优化为触摸网站 . 这比任何其他解决方案更可靠 .
我们的研究表明,大多数桌面用户在点击之前用鼠标移动到屏幕上,因此我们可以在他们点击或悬停任何内容之前检测它们并改变行为 .
这是我们代码的简化版本:
有什么比检查他们是否有触摸屏更好,是检查他们是否使用它,加上更容易检查 .
Working Fiddle
我这样做了;
这个甚至在Windows Surface平板电脑上运行良好!
我使用上面的代码来检测是否触摸,因此我的fancybox iframe将显示在台式计算机上而不是触摸上 . 我注意到,当单独使用blmstr的代码时,Opera Mini for Android 4.0仍然作为非触摸设备注册 . (有谁知道为什么?)
我最终使用:
尝试检测触摸的最大"gotcha"是支持触摸和触控板/鼠标的混合设备 . 即使你're able to correctly detect whether the user' s设备支持触摸,您真正需要做的是检测用户当前使用的输入设备 . 有一个详细的写这个挑战和a possible solution here .
基本上,确定用户是仅触摸屏幕还是使用鼠标/触控板的方法是在页面上注册
touchstart
和mouseover
事件:触摸操作将触发这两个事件,尽管前者(
touchstart
)总是在大多数设备上首先出现 . 因此,依靠这个可预测的事件序列,您可以创建一种机制,动态地向文档根添加或删除can-touch
类,以反映此时文档上用户的 current 输入类型:更多细节here .
看看这个post,它提供了一个非常好的代码片段,用于检测触摸设备时的操作或调用touchstart事件时该怎么办:
不,这是不可能的 . 给出的优秀答案只是部分的,因为任何给定的方法都会产生误报和漏报 . 由于OS API,甚至浏览器也不总是知道是否存在触摸屏,并且事实可能在浏览器会话期间发生变化,特别是对于KVM类型的安排 .
请参阅这篇优秀文章的更多细节:
http://www.stucox.com/blog/you-cant-detect-a-touchscreen/
文章建议你重新考虑那些让你想要检测触摸屏的假设,它们可能是错误的 . (我检查了自己的应用程序,我的假设确实是错误的!)
文章的结论是:
看起来Chrome 24现在支持触摸事件,可能适用于Windows 8.因此,此处发布的代码不再有效 . 我现在不是试图检测浏览器是否支持触摸,而是绑定触摸和点击事件,并确保只调用一个:
然后叫它:
希望这可以帮助 !
自 interaction media features 推出以来,你可以做到:
https://www.w3.org/TR/mediaqueries-4/#descdef-media-any-pointer
要么
我想是一个更彻底的检查 .
我用:
在jQuery mobile 1.0.1中
所有浏览器都支持除Firefox for desktop总是 TRUE 因为Firefox支持桌面支持响应式设计,即使你点击了Touch-Button也没有!
我希望Mozilla能在下一版本中解决这个问题 .
我正在使用Firefox 28桌面 .
关于如何在Javascript中检测页面是否显示在触摸屏设备上,我也遇到了很多不同的选择 . IMO,截至目前,没有真正的选择来正确检测选项 . 浏览器要么在桌面计算机上报告触摸事件(因为操作系统可能是触摸就绪),要么某些解决方案不适用于所有移动设备 .
最后,我意识到我从一开始就遵循了错误的方法:如果我的页面在触摸和非触摸设备上看起来类似,我可能不必担心检测属性:我的情况是通过触摸设备上的按钮停用工具提示,因为它们会导致双击,我只需要点击一下即可激活按钮 .
我的解决方案是 refactor 视图,因此按钮上不需要工具提示,最后我不需要使用 all have their drawbacks 方法从Javascript中检测触摸设备 .
您可以安装现代化器并使用简单的触摸事件 . 这是非常有效的,适用于我测试过的所有设备,包括Windows表面!
我创建了一个jsFiddle
实际答案似乎是考虑上下文的答案:
1) Public site (无登录)
对UI进行编码以同时使用这两个选项 .
2) Login site
捕获登录表单上是否发生鼠标移动,并将其保存为隐藏状态输入 . 该值与登录凭据一起传递并添加到用户的 session ,因此可以在会话期间使用 .
Jquery仅添加到登录页面:
(1对@Dave Burt和1对@Martin Lantzsch的回答)
jQuery v1.11.3
提供的答案中有很多好的信息 . 但是,最近我花了很多时间尝试将所有内容组合成一个有效的解决方案,以完成两件事:
检测到使用的设备是否为触摸屏类型设备 .
检测到设备已被点击 .
除了这篇文章和Detecting touch screen devices with Javascript,我发现Patrick Lauke的这篇文章非常有帮助:https://hacks.mozilla.org/2013/04/detecting-touch-its-the-why-not-the-how/
这是代码......
Important!
*.on( events [, selector ] [, data ], handler )
方法需要有一个选择器,通常是一个元素,可以处理"touchstart"事件,或任何其他与触摸相关的事件 . 在这种情况下,它是超链接元素"a" .现在,您不需要在JavaScript中处理常规鼠标单击,因为您可以使用CSS来使用超链接“a”元素的选择器来处理这些事件,如下所示:
注意:还有其他选择器......
问题
由于混合设备使用触摸和鼠标输入的组合,您需要能够动态更改状态/变量,该状态/变量控制在用户是否为触摸用户时是否应运行一段代码 .
触摸设备也会点击
mousemove
.解决方案
假设加载时触摸为false .
等到
touchstart
事件被触发,然后将其设置为true .如果触发了touchstart,请添加一个mousemove处理程序 .
如果两次mousemove事件触发之间的时间小于20ms,则假设他们使用鼠标作为输入 . 删除不再需要的事件,mousemove对于鼠标设备来说是一个昂贵的事件 .
一旦再次触发touchstart(用户返回使用触摸),该变量将重新设置为true . 并重复这个过程,因此它几乎不可能在20ms内完成它,下一个触摸开始将它重新设置为真 .
在Safari iOS和Chrome for Android上测试过 .
注意:对于MS Surface等的指针事件,不是100%肯定 .
Codepen demo
其中许多工作但要么需要jQuery,要么javascript linters抱怨语法 . 考虑到你的初始问题要求“JavaScript”(不是jQuery,而不是Modernizr)解决这个问题的方法,这里有一个简单的函数,每次都有效 . 这也是你能得到的最小 .
我要提到的最后一个好处是这个代码是框架和设备无关的 . 请享用!
范围jQuery
support
对象:现在你可以在任何地方查看它,如下所示:
到目前为止,这似乎对我来说还不错:
快速注意那些可能想写的人
window.ontouchstart !== undefined
- >请使用micnic答案,因为undefined
不是JavaScript中的关键字 . 如果开发写了类似的东西:开发人员可以根据需要制作任何未定义的内容,您也可以查看
window.ontouchstart = myNonExistingWord;
对那些给出这个答案的人不要不尊重:我很确定我也在我的代码中写了这个;)
当连接鼠标时,可以假设用户具有相当高的命中率(我会说实际上是100%),用户在页面准备好之后将鼠标移动至少一小段距离 - 没有任何点击 . 下面的机制检测到这一点 . 如果检测到,我认为这是缺少触摸支持的标志,或者,如果支持,在使用鼠标时不太重要 . 如果未检测到,则假定触摸设备 .
EDIT 此方法可能不适合所有目的 . 它可用于控制基于加载页面上的用户交互而激活的功能,例如图像查看器 . 下面的代码也会将mousemove事件绑定在没有鼠标的设备上,因为它现在很突出 . 其他方法可能更好 .
粗略地说,它是这样的(抱歉jQuery,但在纯Javascript中类似):