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


416

我已经编写了可在台式机和移动设备上使用的jQuery插件。我想知道JavaScript是否可以检测设备是否具有触摸屏功能。我正在使用jquery-mobile.js来检测触摸屏事件,它可以在iOS,Android等系统上运行,但是我还想根据用户设备是否具有触摸屏来编写条件语句。

那可能吗?


这是document.documentElement中var x ='touchstart'的更好方法;console.log(x)//如果支持则返回true //否则返回false
Risa__B

如果仍然出现新技术,为什么要保护此线程?
安迪·霍夫曼

Answers:


139

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

Modernizr是一种出色的轻量级方法,可在任何站点上执行各种功能检测。

它只是为每个功能将类添加到html元素。

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

html.touch div {
    width: 480px;
}

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

和Javascript(jQuery示例):

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

88
Modernizr不会测试触摸屏。它测试浏览器中是否存在触摸事件。请参阅文档中的“其他测试”部分:modernizr.com/docs/#features-misc
Harry Love

1
如果(Modernizr.touch){/ *做触摸东西/}其他{/很好,不要* /}
Anatoly G

7
以@harrylove的观点来说,自Windows 8发布以来,Modernizr一直错误地将我所有PC浏览器返回为兼容触摸屏。
安东

3
更新:blmstr的答案更好,并且是纯Javascript解决方案。
艾伦·克里斯托弗·托马斯

1
如果Modernizr.touch意外返回undefined,则可能有一个自定义的Modernizr(您可以选择)而不支持触摸事件检测。
亨里克N

679

您是否尝试过使用此功能?(这与Modernizr过去使用的相同。)

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

console.log(is_touch_device());

更新1

document.createEvent("TouchEvent")已开始返回true最新版本的Chrome(第17版)。Modernizr前不久对此进行了更新。在此处检查Modernizr测试

像这样更新您的功能以使其工作:

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

console.log(is_touch_device1());

更新2

我发现以上内容不适用于IE10(在MS Surface上返回false)。解决方法是:

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

console.log(is_touch_device2());

更新3

'onmsgesturechange' in window在某些IE桌面版本中将返回true,因此并不可靠。这可以更可靠地工作:

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

console.log(is_touch_device3());

更新2018

随着时间的流逝,有更多更好的新方法可以对此进行测试。我基本上已经提取并简化了Modernizr的检查方式:

function is_touch_device4() {
    
    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);
}

console.log(is_touch_device4());

他们在这里使用的是非标准touch-enabled媒体查询功能,我认为这是一种怪异和不道德的做法。但是,嘿,在现实世界中,我认为它是可行的。将来(当所有人都支持它们时),这些媒体查询功能可以为您提供相同的结果:pointerhover

查阅Modernizr如何执行此操作来源

有关解释触摸检测问题的好文章,请参阅: Stu Cox:您无法检测到触摸屏


20
双爆炸将值强制转换为布尔值,强制该函数返回truefalse。:你可以阅读更多关于它在这里stackoverflow.com/questions/4686583/...
罗布·弗莱厄蒂

2
这不适用于Opera Mobile 10或Internet Explorer Mobile 6(Windows Mobile 6.5)。
doubleJ 2012年

17
双精度NOT(!!)是多余的,因为in运算符已经计算出一个布尔值。
2012年

11
'onmsgesturechange'即使在非触摸设备(PC)中也评估为正确。 window.navigator.msMaxTouchPoints似乎更准确。 在这里找到它
史蒂夫

6
即使我的屏幕没有触摸传感器,在Windows 8的IE10上它的评估结果也正确。我升级我的旧笔记本电脑从Windows 7到Windows 8
Pwner

120

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

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

您只需要检查一次即可,因为设备不会突然支持或不支持触摸,因此只需将其存储在变量中,便可以更有效地使用它多次。


3
窗口中的“ onmsgesturechange”还可以检测非触摸设备上的“桌面” IE10,因此这不是确定触摸的可靠方法。
马特·斯托

6
这个答案应该是可以接受的,因为它是最好,最简单且最新的答案。在一个函数中,我相信这会更加一致:(return !!('ontouchstart' in window) || !!('msmaxtouchpoints' in window.navigator);结合两个答案)在IE10中也能正常工作!
Yeti 2013年

这应该是公认的答案。'onmsgesturechange' in window即使可以触摸,在IE10桌面上也返回true
Sam Thornton

6
所有您需要的:function isTouchDevice() { return 'ontouchstart' in window || !!(navigator.msMaxTouchPoints);}
GFoley83 2013年

1
甚至GFoley在窗口中建议“ ontouchstart” || !!(navigator.msMaxTouchPoints); 在2014
Tom Andersen

37

使用上面的所有注释,我汇编了以下符合我的需要的代码:

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

我已经在iPad,Android(浏览器和Chrome),Blackberry Playbook,iPhone 4s,Windows Phone 8,IE 10,IE 8,IE 10(带有触摸屏的Windows 8),Opera,Chrome和Firefox上对此进行了测试。

目前,它在Windows Phone 7上无法正常运行,我还无法为该浏览器找到解决方案。

希望有人觉得这有用。


有什么原因不能使用:function is_touch_device(){return !!(窗口中的“ ontouchstart”)|| !!(导航器中的'msmaxtouchpoints'); };
sidonaldson

使用该函数可以工作,但是我通常喜欢使用上面的变量方法,因此它仅需测试一次,并且稍后在代码中进行检查时会更快。我还发现我需要测试以查看msMaxTouchPoints是否大于0,因为Windows 8上没有触摸屏的IE 10的返回值为0作为msMaxTouchPoints。
大卫,

收益true上的窗户上我的Firefox 32 7 :(
VSYNC

Windows 8上的Firefox 33和33.1在我的系统上均正确显示false。如果将Firefox升级到最新版本,它仍然返回true吗?您是否在计算机上安装了设备,可能使Firefox错误地认为您的计算机具有触摸功能?
大卫

>>>窗口中的'ontouchstart'>>> Ubuntu上真正的FF 51.0.1
拉维·加迪亚

25

由于引入了交互媒体功能,您可以轻松做到:

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

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

更新(由于评论):上述解决方案是检测“粗指针”(通常是触摸屏)是否是主要输入设备。如果您想确定某个设备(如鼠标)是否也具有触摸屏,则可以any-pointer: coarse改用它。

有关更多信息,请参见此处:检测浏览器没有鼠标并且仅是触摸式


3
这是迄今为止最好的解决方案,谢谢!尽管我建议您使用,(pointer: coarse)因为您极有可能只针对主要输入。由于少数不支持的浏览器仅是台式机,因此可以在生产中使用。在css-tricks上有一篇很棒的文章。
Fabian von Ellerts,

2
这是我测试过的唯一适用于各种情况的解决方案。谢谢!
kaiserkiwi

20

我喜欢这一个:

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

alert(isTouchDevice());

12
无需使用三元表达式返回布尔值。只需使用表达式即可返回布尔值。function isTouchDevice(){ return (window.ontouchstart !== undefined); }
Tim Vermaelen 2013年

1
您也可以使用:var isTouch = 'ontouchstart' in window;,但是不适用于最新的Chrome(v31),var isTouch = 'createTouch' in window.document;仍可以使用。
奥利维尔2014年

2
正如先前接受的问题的评论中已经提到的那样。“ Modernizr不会测试触摸屏。它会测试浏览器中是否存在触摸事件”。从技术上来说,您的函数是hasTouchEvents()而不是isTouchDevice()
hexalys

请注意,仅类似方法测试touchstart将无法将Surface识别为触摸设备,因为IE改用pointer事件。
CookieMonster 2014年

1
也许@Nis是正确的,但是在Firefox 39中,它正确返回了false。
Dan Dascalescu 2015年

17

如果您使用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将为您提供更广泛的检测到的Microsoft移动设备Windows Phone

另请参阅此问题


8
“做一些棘手的事情”和“做不到的事情”有很多奖励积分
Lee Saxon 2015年

您需要多次检查同一台设备,并且在只能使用一个设备时执行多个Regexes。另外,您正在执行不区分大小写的正则表达式,但是字符串已经小写。
caesarsol

1
这应该足够了:/(iphone|ipod|ipad|android|iemobile|blackberry|bada)/.test(window.navigator.userAgent.toLowerCase())
caesarsol

有什么理由要小写或使匹配的字符不区分大小写?什么时候使用“ iOS”,“ Android”或“ IEMobile”使用其他大小写格式?
Henrik N

14

我们尝试了modernizr实现,但是检测触摸事件不再是一致的(IE 10在Windows桌面上具有触摸事件,IE 11可以正常工作,因为已经删除了触摸事件并添加了指针api)。

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

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

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

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

当今的计算机同时具有触摸和鼠标功能……您必须与众不同。绝对必须知道它是仅触摸屏,鼠标还是两者。3个不同的州。
vsync 2014年

1
是的,您是对的,但这很难。最好的情况是,您的应用程序设计为可被任何输入控制器使用,并且不在乎用户是否拥有触摸屏,鼠标,键盘或全部。
Martin Lantzsch 2014年

1
用户的行为比用户拥有哪种设备的真实信息更有价值。当您知道用户有鼠标,触摸屏和键盘时,该怎么办?处理行为(移动,触摸移动,按下按键等)。用户可以在“运行时”更改输入类型,这是一个真正的难题,当您正在开发使用8到5而无需重新加载的真实应用程序时。
马丁·兰兹

2
+1实用上这是对我最好的答案。例如,我有数据网格。这些数据网格将显示一个用于触摸以进行编辑的“编辑图标”,或一个用于显示更多选项的上下文菜单。如果检测到鼠标移动,则删除图标(在网格上节省空间),用户可以双击或右键单击。
prograhammer

3
触摸设备上的chrome偶尔会触发mousemove
pstanton

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
}

无法检测到Windows表面平板电脑
Dan Beaulieu 2015年

@DanBeaulieu能否请您特定于设备,因为我有可以正常使用的Windows Phone,而且我在QA:ED应用程序中使用了它,因此我将再次对其进行检查并更新答案。抱歉给您带来不便
Aamir Shahzad 2015年

不知道哪一年是属于同事的Windows Surface Pro。添加modernizr之后,我们就可以使用它。
Dan Beaulieu 2015年

这可以在我的Windows 7计算机上正确报告“非触摸”,并在带有触摸屏的Windows 8笔记本电脑和Android 4.4 MotoX手机上进行触摸。
克莱·尼科尔斯

给我的Mac上的Chrome(46)提供了误报
Patrick Fabrizius

9

除了检查他们是否有触摸屏之外,还有其他要比检查他们是否正在使用触摸屏更好的方法,而且检查起来更容易。

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

6

即使在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");
}
}

4

我使用上面的代码片段来检测是否触摸,因此我的fancybox iframe将显示在台式计算机上而不是触摸上。我注意到,仅使用blmstr的代码时,适用于Android 4.0的Opera Mini仍在注册为非触摸设备。(有人知道为什么吗?)

我最终使用:

<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>

您能否解释一下,为什么不对单个正则表达式使用单个匹配调用/iPhone|iPod|iPad|Android|BlackBerry/
user907860 2014年

Opera Mini在Opera的服务器上而不是在设备本身上进行渲染,所以这种方式有点奇怪。
bluesmoon

4

试图检测触摸的最大“陷阱”是在同时支持触摸和触控板/鼠标的混合设备上。即使您能够正确检测用户设备是否支持触摸,您真正需要做的就是检测用户当前正在使用的输入设备。有关此挑战的详细记录,可能的解决方案

基本上,确定用户是刚刚触摸屏幕还是使用鼠标/触控板的方法是在页面上注册a touchstartmouseoverevent:

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向文档根目录添加或删除类,以反映此时用户在文档上的当前输入类型:

;(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
})();

更多细节在这里


3

查看这篇文章,它提供了一个非常不错的代码片段,用于检测到触摸设备时执行的操作或调用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();
}

3

我会避免使用屏幕宽度来确定设备是否为触摸设备。想想Windows 8,有比699px大得多的触摸屏。Navigatior.userAgent可能会很好地覆盖假阳性。

我建议您在Modernizr上检查此问题

您是否要测试该设备是否支持触摸事件或是触摸设备。不幸的是,那不是同一回事。


3

不,不可能。给出的出色答案永远都是局部的,因为任何给定的方法都会产生假阳性和假阴性。由于OS API,即使浏览器也并不总是知道是否存在触摸屏,并且事实可能会在浏览器会话期间发生变化,尤其是在使用KVM类型的布置时。

请参阅这篇出色的文章中的更多细节:

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

本文建议您重新考虑使您想要检测触摸屏的假设,它们可能是错误的。(我检查了自己的应用程序,但我的假设确实是错误的!)

本文的结论是:

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

对于事件和交互,假设任何人都可以拥有触摸屏。相互实现键盘,鼠标和触摸交互,确保彼此之间不会相互阻塞。


3

这些工作很多,但要么需要jQuery,要么需要javascript linter抱怨语法。考虑到您的第一个问题需要一种“ JavaScript”(不是jQuery,不是Modernizr)的解决方案,这是一个每次都能使用的简单函数。它也尽可能地少。

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

console.log(isTouchDevice());

我要提到的最后一个好处是该代码与框架和设备无关。请享用!


function isTouchScreen() { return window.matchMedia('(hover: none)').matches;}这对我有用,所以我在这里为这个答案做一个贡献,因为当Google将我带到这里时,我也期待一个香草JS线程。
丹尼尔·拉维多尼奥·德利马

2

Chrome 24现在似乎支持触摸事件,可能适用于Windows8。因此此处发布的代码不再起作用。现在,我要绑定触摸和单击事件,并确保仅调用一个事件,而不是尝试检测浏览器是否支持触摸:

myCustomBind = function(controlName, callback) {

  $(controlName).bind('touchend click', function(e) {
    e.stopPropagation();
    e.preventDefault();

    callback.call();
  });
};

然后调用它:

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

希望这可以帮助 !



2

除桌面版Firefox外,所有受支持的浏览器始终为TRUE的Firefox因为即使您单击“触摸按钮”,也无法为开发人员使用Firefox支持开发人员的响应式设计!

我希望Mozilla在下一版本中可以解决此问题。

我正在使用Firefox 28桌面。

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

它仍然是32.0版,他们还没有修复!疯。为什么这不能切换?这总是返回true:(
vsync

2

jQuery v1.11.3

提供的答案中有很多很好的信息。但是,最近,我花了很多时间尝试将所有内容实际结合到一个可行的解决方案中,以完成两件事:

  1. 检测正在使用的设备是触摸屏类型的设备。
  2. 检测到设备被点击。

除了这篇文章和使用Javascript检测触摸屏设备之外,我发现Patrick Lauke的这篇文章非常有帮助: https /

这是代码...

$(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 )方法需要具有一个选择器,通常是一个元素,可以处理“ touchstart”事件或与触摸相关的任何其他类似事件。在这种情况下,它是超链接元素“ a”。

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

/* unvisited link */
a:link 
{

}

/* visited link */
a:visited 
{

}

/* mouse over link */
a:hover 
{

}

/* selected link */
a:active 
{

}

注意:还有其他选择器...


1
var isTouchScreen = 'createTouch' in document;

要么

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

我想这将是更彻底的检查。


3
最好ua提及navigator.userAgent。此外,如果有人以非全屏模式打开浏览器,则通过屏幕宽度进行检测也会产生错误的结果。
2011年

1

我用:

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

在jQuery mobile 1.0.1中


1

对于如何在Javascript中检测页面是否显示在触摸屏设备上,我也进行了很多尝试,其中包括不同的选择。IMO,截至目前,尚无实际选项可正确检测到该选项。浏览器要么报告台式机上的触摸事件(因为操作系统可能支持触摸),要么某些解决方案无法在所有移动设备上正常工作。

最后,我意识到我从一开始就采用了错误的方法:如果我的页面在触摸和非触摸设备上看起来都相似,那么我也许根本不必担心检测属性:我的情况是在触摸设备上的按钮上停用工具提示,因为它们会导致双击,而我希望单击即可激活该按钮。

我的解决方案是重构视图,以使按钮上不需要工具提示,最后,我不需要使用所有都有缺点的方法从Javascript中检测触摸设备。


1

您可以安装现代化器并使用简单的触摸事件。这非常有效,并且可以在我测试过的所有设备(包括Windows表面)上使用!

我创建了一个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;
    }
}

3
欢迎来到SO!单独的代码(如未注释的代码)很少构成答案。您可以通过添加摘要说明来改善此答案。
ebarr

1

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

1)公共站点(无登录)
对UI进行编码以使其与这两个选项一起使用。

2)登录站点
捕获是否在登录表单上发生了鼠标移动,并将其保存到隐藏的输入中。该值与登录凭据一起传递并添加到用户的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);
    });
} 

(+1回复@Dave Burt,+ 1回复@Martin Lantzsch)


1

问题

由于混合设备使用触摸和鼠标输入的组合,因此您需要能够动态更改状态/变量,该状态/变量控制如果用户是触摸用户,是否应该运行一段代码。

触摸设备也会触发 mousemove在点击时。

  1. 假设触摸在加载时为假。
  2. 等待touchstart事件触发,然后将其设置为true。
  3. 如果触发touchstart,请添加mousemove处理程序。
  4. 如果两次触发mousemove事件之间的时间少于20ms,则假定它们使用鼠标作为输入。删除事件,因为它不再需要,并且mousemove对于鼠标设备来说是一项昂贵的事件。
  5. 再次触发touchstart(用户返回使用touch)后,该变量将设置回true。并重复此过程,以便以动态方式确定它。如果由于某种奇妙的原因,mousemove很快就两次被触发两次(在我的测试中,几乎不可能在20ms内完成操作),则下一次touchstart会将其设置为true。

已在Safari iOS和Android版Chrome上测试。

注意:不能100%确定MS Surface等的指针事件。

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 < 20) {
      isUsingTouch = false;
      document.removeEventListener('mousemove', mousemoveHandler);
    }

    time = now;
  }
})();

// add listeners
if (supportsTouch) {
  document.addEventListener('touchstart', touchHandler);
} else if (navigator.maxTouchPoints || navigator.msMaxTouchPoints) {
  document.addEventListener('pointerdown', touchHandler);
}

1

实际上,我研究了这个问题并考虑了所有情况。因为这也是我项目中的大问题。因此,我达到以下功能,它适用于所有设备上所有浏览器的所有版本:

const isTouchDevice = () => {
  const prefixes = ['', '-webkit-', '-moz-', '-o-', '-ms-', ''];
  const mq = query => window.matchMedia(query).matches;

  if (
    'ontouchstart' in window ||
    (window.DocumentTouch && document instanceof DocumentTouch)
  ) {
    return true;
  }
  return mq(['(', prefixes.join('touch-enabled),('), 'heartz', ')'].join(''));
};

提示:绝对会isTouchDevice返回boolean值。


0

范围jQuery support对象:

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

现在您可以在任何地方检查它,如下所示:

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

0

到目前为止,这对我来说似乎还不错:

//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)
}

0

当连接了鼠标时,可以假定用户以相当高的命中率(实际上可以说是100%)在页面准备好后用户至少将鼠标移动了很小的距离-无需单击任何鼠标。下面的机制可以检测到这一点。如果检测到,我认为这是缺少触摸支持的标志,或者如果支持,则在使用鼠标时意义不大。如果未检测到,则假定为触摸设备。

编辑此方法可能无法满足所有目的。它可用于控制基于已加载页面上的用户交互(例如图像查看器)激活的功能。下面的代码还会使mousemove事件绑定在没有鼠标的设备上,因为它现在很突出。其他方法可能更好。

大致来说,它是这样的(对不起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;
}));
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.