在触摸屏设备上检测鼠标

时间:2015-02-18 21:39:10

标签: javascript jquery touch

我使用以下代码来检测设备是否是触摸设备:

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

if(isTouchDevice)
{
    $('body').addClass('yes-touch');
}
else
{
    $('body').addClass('no-touch');
}

我使用此功能仅显示:hover状态,因为它不是触控设备(因为大多数触控设备会将水龙头解释为悬停)。

.no-touch .element:hover {
    color: red;
}

问题是,我们办公室中的一台PC是一体化的触摸屏PC,这意味着当使用鼠标时,悬停状态不会发生。

有没有办法弄清楚鼠标是否在触摸屏设备上使用?换句话说,在使用鼠标时应该应用no-touch类,并且在使用触摸屏时应用yes-touch类。

3 个答案:

答案 0 :(得分:4)

截至今天,没有万无一失的铁定方式。现代人员,几乎是特征检测方面的专家,最近有这样的说法:

https://github.com/Modernizr/Modernizr/issues/869#issuecomment-57891034

  

所有这一切的最终结果是您无法检测到鼠标的使用情况   一种符合Modernizr可靠性水平的方式   记入。对于我们的意图和目的,它是不可检测的。

     

如果您,未来的旅行者,希望尝试检测鼠标用户,那么   以下是我能提供的最佳指南。

     
      
  1. 别。认真。仅仅因为用户拥有“鼠标”并不意味着这一点   他们没有多种其他形式的输入。你应该尝试一下   很难避免做出任何基于变化的UI / UX决策   根据鼠标用户与a的截然相反的想法   触摸屏用户(或其他任何类型的用户)。做东西   通用
  2.   
  3. 如果你必须,只关心IE 10和11,那么IE的   PointerEvent值得一试。外面的支持非常糟糕   这两个(可能是未来的IE版本)。
  4.   
  5. 你可以附上一个   听取身体上的'悬停'事件,如果是真的话,那么   用户可能有一个鼠标。这种方法的缺点包括   触摸事件在点击/触摸时短暂触发悬停事件,所以你可以   得到误报。
  6.   
  7. 嗅探移动用户代理。这是一个坏主意,   并且违背了Modernizr的核心。请不要这样做。
  8.   

所以对我来说#1几乎可以总结一下。但是,这回答了你的问题,但没有给你一个解决方案。你在办公室提到“ 我们的 PC之一......”这是一个偶然的内部唯一应用吗?我偶尔会遇到内部特殊用途或一页外页可能因任何原因需要进行个别处理的情况(例如我们的员工之一使用带有鼠标的触摸式AIO)。然后,我要做的是在网址的末尾添加?hasmouse,并为用户提供指向书签的链接。然后在你的var isTouchDevice之后但在if之前的javascript中,插入此代码来撤消它:

if (location.search == '?hasmouse') {
    isTouchDevice = false;
}

再说一遍,这对于内部使用来说是一种没有多余的方式。

答案 1 :(得分:0)

我已经使用了一段时间,它似乎可靠地工作。如果有时候我觉得它值得,但确实有效。

这里的想法是捕获实际触地事件以触发触摸模式并使用mousemove触发鼠标模式。问题是IE不会触发触摸事件,而是指针事件。关于指针事件的好处是你可以检查它是鼠标还是触摸!

问题是所有其他浏览器在触摸事件之后触发了一个假的鼠标移动。这真是令人发狂!

您可以看到它适用于此codepen

//首先检查这是否是触控设备:

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

//我们稍后需要的一些变种

var lastTouch = 0
var lastCheck = 0

//然后设置我们的事件监听器:

function initEvents() {

  //handle touch/mouse devices detect mouse so that touch is toggled off
  if (this.isTouch) {

    $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) {
      e = e.originalEvent
        //browser has pointer events
      var pe = window.PointerEvent || window.MSPointerEvent

      // handle ie pointer events (polyfill functions are at bottom of answer)

      if (e.type == msPointerEvent('move')) {
        var touchEvent = msPointerType(e) == 'touch'
        if (touchEvent)
          lastTouch = e.timeStamp;
        if (!this.isTouch && touchEvent)
          return setupTouch.call(this, true)
        else if (this.isTouch && !touchEvent)
          return setupTouch.call(this, false)
      }

      // Handle all other browser touch events
      if (e.type == "touchstart") {
        console.log('touchstart fired')
        lastTouch = e.timeStamp;
        if (!this.isTouch)
          setupTouch.call(this, true);
      }

      // test mouse move and set up mouse mode if real
      else if (!pe && e.type == "mousemove" && this.isTouch) {
        if (realMouseDown.call(this, e)) {
          setupTouch.call(this, false)
        }
      }
    }.bind(this));
  }
}
initEvents()

//这是我们变得聪明的地方。事实证明,假的鼠标移动将在不到500ms的触摸时触发,因此我们使用它来检测假货。然后当然为IE做一些特别的事情:

function realMouseDown(e) {

  var touchDif = e.timeStamp - lastTouch
  var mouseDif = e.timeStamp - lastCheck

  // false mouse event will get fired within 500ms of a touch (touchDif > 500)
  // (required for all browsers false mouse after touch event)
  var real = touchDif > 500

  lastCheck = e.timeStamp;
  console.log('real=', real, ' mDif ='+mouseDif, ' tDif ='+touchDif)

  return real
}

//现在对于一些IE polyfill,因为他们似乎无法决定做什么。

// IE pointer event polyfill
function msPointerEvent(type) {

  var n = ""

  if (window.PointerEvent) // IE 11
    n = 'pointer' + type
  else if (window.MSPointerEvent) // IE 10
    n = 'MSPointer' + type[0].toUpperCase() + type.substr(1);
  return n
}

// IE pointer type polyfill
function msPointerType(e) {

  var pt = ['zero', 'one', 'touch', 'pen', 'mouse']

  return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType]
}

//最后做你需要的......

// make required changes for touch / mouse
var $output = $('#output')
function setupTouch(state) {
  console.log('TouchMode=', state)
  if (state)
    this.isTouch = true
  else
    this.isTouch = false
  $output.html('Touch mode changed to = '+state)

}

//First check if this is a touch device:

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

// Some vars we'll need later
var lastTouch = 0
var lastCheck = 0

//Then set up our event listeners:

function initEvents() {

  //handle touch/mouse devices detect mouse so that touch is toggled off
  if (this.isTouch) {

    $(document).on(" touchstart mousemove " + msPointerEvent('move'), function(e) {
      e = e.originalEvent
        //browser has pointer events
      var pe = window.PointerEvent || window.MSPointerEvent

      // handle ie pointer events (polyfill functions are at bottom of answer)

      if (e.type == msPointerEvent('move')) {
        var touchEvent = msPointerType(e) == 'touch'
        if (touchEvent)
          lastTouch = e.timeStamp;
        if (!this.isTouch && touchEvent)
          return setupTouch.call(this, true)
        else if (this.isTouch && !touchEvent)
          return setupTouch.call(this, false)
      }

      // Handle all other browser touch events
      else if (e.type == "touchstart") {
        console.log('touchstart fired')
        lastTouch = e.timeStamp;
        if (!this.isTouch)
          setupTouch.call(this, true);
      }

      // test mouse move and set up mouse mode if real
      else if (!pe && e.type == "mousemove" && this.isTouch) {
        if (realMouseDown.call(this, e)) {
          setupTouch.call(this, false)
        }
      }
    }.bind(this));
  }
}
initEvents()
  // Here is where we get clever. It turns out that the fake mousemove will fire in less than 500ms of the touch so we use that to detect fakes:

function realMouseDown(e) {

  var touchDif = e.timeStamp - lastTouch
  var mouseDif = e.timeStamp - lastCheck

  // false mouse event will get fired within 500ms of a touch (touchDif > 500)
  // (required for all browsers false mouse after touch event)
  var real = touchDif > 500

  lastCheck = e.timeStamp;
  console.log('real=', real, ' mDif =' + mouseDif, ' tDif =' + touchDif)

  return real
}

// IE pointer event polyfill
function msPointerEvent(type) {

  var n = ""

  if (window.PointerEvent) // IE 11
    n = 'pointer' + type
  else if (window.MSPointerEvent) // IE 10
    n = 'MSPointer' + type[0].toUpperCase() + type.substr(1);
  return n
}

// IE pointer type polyfill
function msPointerType(e) {

  var pt = ['zero', 'one', 'touch', 'pen', 'mouse']

  return typeof e.pointerType == 'string' ? e.pointerType : pt[e.pointerType]
}

// make required changes for touch / mouse
var $output = $('#output')


function setupTouch(state) {
  console.log('TouchMode=', state)
  if (state) {
    this.isTouch = true
    $output.addClass('is-touch')
  } else {
    this.isTouch = false
    $output.removeClass('is-touch')
  }
  $output.html('Touch mode changed to = ' + state)

}
body {
  pointer-evetns: none;
}
#output.is-touch {
  background-color: blue;
  color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="output">
  Touch or movethe mose on the result window to change the TouchMode state.
</div>

答案 2 :(得分:0)

您可以检查指向您对象的指针事件的类型。

请在下面查看悬停示例:

$('.element').on('pointerenter', function (e) {
    if (e.pointerType == 'mouse') {
        $(this).addClass('hover');
    }
}).on('pointerleave', function (e) {
    if (e.pointerType == 'mouse') {
        $(this).removeClass('hover');
    }
});

并使用您的CSS:

.element.hover {
    color: red;
}