Я использовал это некоторое время, и он работает надежно. Я размышлял, если он того стоит, но он работает.
Идея здесь состоит в том, чтобы захватить реальные события приземления, чтобы вызвать сенсорный режим и использовать mousemove для запуска режима мыши. Проблема в том, что IE не вызывает события касания, а события указателя. Самое замечательное в событиях указателей - вы можете проверить, есть ли это мышь или прикосновение!
Проблема заключается в том, что все другие браузеры запускают поддельную mousemove сразу после события касания. Это действительно безумие!
Вы можете видеть, что работать над этим 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()
// Здесь мы умны. Оказывается, поддельный мусмове будет стрелять менее чем за 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>
Хотя это может быть позиция реформатором (по уважительной причине я должен сказать), это не означает, что никогда не бывает случая, когда это необходимо. Оп спросил, есть ли способ ... – arctelix
@arctelix Рекомендация не делать этого не была декларативной из-за того, что нет возможного варианта использования. Это связано с тем, что нет надежного способа сделать это так, чтобы он работал эффективно и во всех основных браузерах на данный момент (возможно, когда-нибудь). Код, который вы опубликовали, является хорошим (и умным), но вы полагаетесь на событие <500 мс, и его подводные камни рассматриваются в связи с обсуждением Modernizr. – jwhazel
Я полностью понимаю, почему модернизатор решил не делать этого и полностью согласен с тем, что они не должны этого делать, но опубликованное решение действительно работает для тех, кто хочет жить на грани. Я понимаю все теоретические проблемы с надежностью. Тем не менее, это отлично работает для меня, во всех браузерах, поддерживающих touch & mouse. Теоретически, может быть неправильный результат, но следующий прикосновение или движение мыши исправит его. Я разрабатываю на окнах с сенсорным экраном, чтобы он постоянно тестировался. Моя единственная забота - погода, в которой участвуют два дополнительных слушателя событий. – arctelix