我已经使用了一段时间,它似乎可以可靠地工作。有时我会觉得值得,但它确实有效。
这里的想法是捕获实际的触摸事件来触发触摸模式并使用 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()
// 这是我们变得聪明的地方。事实证明,假的 mousemove 会在不到 500 毫秒的触摸内触发,所以我们用它来检测假货。然后当然要为 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>