Chrome 处理触摸屏上的鼠标和触摸事件

uplii1fm  于 2023-05-04  发布在  Go
关注(0)|答案(7)|浏览(347)

我写的网络应用程序应该支持鼠标和触摸交互。为了测试我使用触摸屏设备与Windows 7.我尝试在最新的Firefox和Chrome canary中嗅探触摸事件,并得到以下结果:
在触摸Firefox触发触摸和相应的鼠标事件。Chrome会触发touchstart/mousedowntouchend/mouseup对,但mousemove的触发方式非常奇怪:1/2次,而touchmove.
所有鼠标事件都照常处理。
有没有办法在现代触摸屏上同时处理鼠标和触摸事件?如果Firefox触发了一对触摸和鼠标事件,在touchmovemousemove上会发生什么?我应该将所有鼠标事件转换为触摸还是相反?我希望找到正确的方法来创建响应式界面。

6ojccjat

6ojccjat1#

你真的不能提前预测哪些事件要听(例如。对于所有你知道的USB触摸屏可以得到插入后,您的网页已加载)。
相反,您应该始终侦听触摸事件和鼠标事件,但在您处理的触摸事件上调用preventDefault(),以防止(现在是多余的)鼠标事件被触发。详情请参见http://www.html5rocks.com/en/mobile/touchandmouse/

0yg35tkg

0yg35tkg2#

您应该检查触摸界面的可用性并根据此绑定事件。
你可以这样做:

(function () {
    if ('ontouchstart' in window) {
        window.Evt = {
            PUSH : 'touchstart',
            MOVE : 'touchmove',
            RELEASE : 'touchend'
        };
    } else {
        window.Evt = {
            PUSH : 'mousedown',
            MOVE : 'mousemove',
            RELEASE : 'mouseup'
        };
    }
}());

// and then...

document.getElementById('mydiv').addEventListener(Evt.PUSH, myStartDragHandler, false);

如果你想同时处理这两个事件,而浏览器不能很好地将触摸事件转换为鼠标事件,你可以捕获触摸事件并停止它们-然后相应的鼠标事件不应该被浏览器触发(你不会有双重事件),你可以自己触发它作为鼠标事件或只是处理它。

var mydiv = document.getElementsById('mydiv');
mydiv.addEventListener('mousemove', myMoveHandler, false);
mydiv.addEventListener('touchmove', function (e) {
    // stop touch event
    e.stopPropagation();
    e.preventDefault();

    // translate to mouse event
    var clkEvt = document.createEvent('MouseEvent');
    clkEvt.initMouseEvent('mousemove', true, true, window, e.detail, 
                 e.touches[0].screenX, e.touches[0].screenY, 
                 e.touches[0].clientX, e.touches[0].clientY, 
                 false, false, false, false, 
                 0, null);
    mydiv.dispatchEvent(clkEvt);

    // or just handle touch event
    myMoveHandler(e);
}, false);
vlf7wbxs

vlf7wbxs3#

这个线程上的解决方案已经过时了--对于那些在2021年仍然在这里登陆的人(比如我)来说,有一个新的W3指针事件规范。这些事件将鼠标和触摸结合在一起。
https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events
https://www.w3.org/TR/pointerevents/

a64a0gku

a64a0gku4#

MouseEvents和TouchEvents在技术上不提供完全相同的功能,但在大多数情况下,它们可以互换使用。该解决方案并不偏爱其中一个,因为用户可能同时具有鼠标和触摸屏。相反,它允许用户使用他们想要的任何输入设备,只要他们在改变输入之前等待至少五秒。此解决方案忽略触摸屏设备上点击屏幕时的鼠标指针模拟。

var lastEvent = 3  ;
var MOUSE_EVENT = 1;
var TOUCH_EVENT = 2 ; 
 

element.addEventListener('touchstart', function(event)
		{
			 
			if (lastEvent === MOUSE_EVENT  )
			{
				var time =  Date.now() - eventTime  ;  
				if ( time > 5000 ) 
				{
					eventTime = Date.now() ;
					lastEvent = TOUCH_EVENT ;
					interactionStart(event) ;
				} 
			}
			else 
			{
				lastEvent = TOUCH_EVENT ; ;
				eventTime = Date.now() ;
				interactionStart(event)  ; 
			}
			 
		}) ;	

		element.addEventListener('mousedown',	function(event)
		{
			
			if (lastEvent === TOUCH_EVENT  )
			{
				var time =  Date.now() - eventTime  ;	
				if ( time > 5000 ) 
				{
					eventTime = Date.now() ;
					lastEvent = MOUSE_EVENT ;
					interactionStart(event) ;
				} 
			}
			else 
			{
				lastEvent=  MOUSE_EVENT ; 
				eventTime = Date.now() ;
				interactionStart(event)  ; 
			}
		}) ;  

function interactionStart(event) // handle interaction (touch or click ) here.
{...}

这绝不是一个双赢的解决方案,我已经使用了几次,并没有发现它的问题,但公平地说,我通常只是用它来启动动画时,画布点击,或提供逻辑,把一个div变成一个按钮。我把它留给你们所有人来使用这段代码,寻找改进和帮助来改进这段代码。(如果你没有找到更好的解决方案)。

l0oc07j2

l0oc07j25#

我发现这个帖子是因为我有一个类似的和更复杂的问题:
假设我们创建了一个具有箭头NEXT/PREVIOUS的启用了js的可滚动区域,我们不仅希望响应触摸和鼠标事件,而且希望在用户继续按下屏幕或按住他/她的鼠标时反复触发它们!
重复的事件将使我的下一个按钮前进2个位置,而不是一个!
在闭包的帮助下,一切似乎都是可能的:

(1)首先创建一个自调用函数进行变量隔离:

(function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));

(2)然后,添加您的私有变量,它将保存来自setTimeout()的内部状态:

/*
 * Primary events for handlers that respond to more than one event and devices  
 * that produce more than one, like touch devices.
 * The first event in browser's queue hinders all subsequent for the specific 
 * key intended to be used by a handler.
 * Every key points to an object '{primary: <event type>}'.
 */
var eventLock = {};
// Process ids based on keys.
var pids = {};
// Some defaults
var defaults = {
   pressDelay: 100 // ms between successive calls for continuous press by mouse or touch
}

(3)事件锁功能:

function getEventLock(evt, key){
   if(typeof(eventLock[key]) == 'undefined'){
      eventLock[key] = {};
      eventLock[key].primary = evt.type;
      return true;
   }
   if(evt.type == eventLock[key].primary)
      return true;
   else
      return false;
}
function primaryEventLock(evt, key){
   eventLock[key].primary = evt.type;
}

(4)附加您的事件句柄:

function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}

事件mousedowntouchstart的触发将在同时支持这两个事件的设备上产生对处理程序的双重调用(可能首先触发)。这同样适用于mouseuptouchend
我们知道输入设备(实际上是整个图形环境)按顺序产生事件,所以我们不关心哪个先触发,只要在私有eventLock.next.primaryeventLock.previous.primary上设置一个特殊键,分别用于从处理程序next*()previous*()捕获的第一个事件。
是事件类型,因此第二个、第三个等事件总是失败者,它们不会在锁函数eventLock()primaryEventLock()的帮助下获得锁。

(5)以上可以在事件处理函数的定义中看到:

function previousStart(evt){
   // 'race' condition/repetition between 'mousedown' and 'touchstart'
   if(!getEventLock(evt, 'previous'))
      return;

   // a. !!!you have to implement this!!!
   previous(evt.target);

   // b. emulate successive events of this type
   pids.previous = setTimeout(closure, defaults.pressDelay);

   // internal function repeats steps (a), (b)
   function closure(){
      previous(evt.target);
      primaryEventLock(evt, 'previous');
      pids.previous = setTimeout(closure, defaults.pressDelay);
   }
};
function previousEnd(evt){
      clearTimeout(pids.previous);
};

类似于nextStartnextEnd
这个想法是,无论谁在第一次(触摸或鼠标)之后,都不会在function eventLock(evt, key)的帮助下获得,并停止在那里。
打开此锁的唯一方法是在步骤(4)中触发termination事件处理程序*End()previousEndnextEnd
我还用一种非常聪明的方式处理了在会话中间连接的触摸设备的问题:我注意到,连续按下超过defaults.pressDelay的时间,会连续调用only当时的主事件的回调函数(原因是没有结束事件处理程序终止callabck)!

touchstart event
closure
closure
....
touchend event

我定义了primary用户正在使用的设备,所以,你所要做的就是长按一下,你的设备立即在闭包内的primaryEventLock(evt, 'previous')的帮助下成为primary
另外,请注意,执行previous(event.target)所需的时间应该小于defaults.pressDelay

(6)最后,让我们将init()暴露到全局作用域:

myScroll.init = init;

您应该将对previous(event.target)的调用替换为当前的问题:fiddle
另外,请注意,在 (5 b) 中有另一个流行问题的解决方案 * 我们如何将参数传递给从setTimeout() * 调用的函数,即setTimeout(previous, defaults.pressDelay)缺少参数传递机制。

e5njpo68

e5njpo686#

我一直在使用这个jQuery助手来绑定触摸和点击事件。

(function ($) {
$.fn.tclick = function (onclick) {
    this.bind("touchstart", function (e) { onclick.call(this, e); e.stopPropagation(); e.preventDefault(); });
    this.bind("click", function (e) { onclick.call(this, e); });   //substitute mousedown event for exact same result as touchstart         
    return this;
  };
})(jQuery);
qf9go6mv

qf9go6mv7#

更好的解决方案和最新使用案例

如果你的鼠标和触摸事件做类似的活动,那么最好使用指针事件它将处理这两种情况。
例如,PointerDown将同时适用于MouseDownTouchStart
https://usefulangle.com/post/27/javascript-advantage-of-using-pointer-events-over-mouse-touch-events
https://developer.mozilla.org/en-US/docs/Web/API/Pointer_events

相关问题