Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/ant/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript 在触摸屏上处理鼠标和触摸事件_Javascript_Google Chrome_Firefox_Touch_Touchscreen - Fatal编程技术网

Javascript 在触摸屏上处理鼠标和触摸事件

Javascript 在触摸屏上处理鼠标和触摸事件,javascript,google-chrome,firefox,touch,touchscreen,Javascript,Google Chrome,Firefox,Touch,Touchscreen,我正在编写web应用程序,它应该支持鼠标和触摸交互。 对于测试,我使用带有Windows7的触摸屏设备。我尝试在最新的Firefox和Chrome canary中嗅探触摸事件,结果如下: 触控Firefox触发触控和相应的鼠标事件。 Chrome启动了touchstart/mousedown,touchend/mouseup对,但mousemove以非常奇怪的方式启动:在touchmove时启动了一/两次 所有鼠标事件都将一如既往地处理 在现代触摸屏上,有没有办法同时处理鼠标和触摸屏?如果Fir

我正在编写web应用程序,它应该支持鼠标和触摸交互。 对于测试,我使用带有Windows7的触摸屏设备。我尝试在最新的Firefox和Chrome canary中嗅探触摸事件,结果如下:

触控Firefox触发触控和相应的鼠标事件。 Chrome启动了
touchstart/mousedown
touchend/mouseup
对,但
mousemove
以非常奇怪的方式启动:在
touchmove
时启动了一/两次

所有鼠标事件都将一如既往地处理

在现代触摸屏上,有没有办法同时处理鼠标和触摸屏?如果Firefox触发了一对触摸和鼠标事件,那么Chrome中的
touchmove
mousemove
会发生什么?我应该将所有鼠标事件转换为触摸还是反之?我希望找到创建响应界面的正确方法。

您应该检查触摸界面的可用性,并据此绑定事件

您可以这样做:

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

你无法预先预测要监听哪些事件(例如,据你所知,在你的页面加载后,USB触摸屏可能会被插入)


相反,您应该始终同时侦听触摸事件和鼠标事件,但对您处理的触摸事件调用preventDefault(),以防止触发(现在是冗余的)鼠标事件。有关详细信息,请参阅。

我一直在使用这个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);

MouseeEvents和TouchEvents在技术上并不提供完全相同的功能,但在大多数情况下,它们可以互换使用。这种解决方案并不偏向于一种,因为用户可能同时拥有鼠标和触摸屏。相反,它允许用户使用他们想要的输入设备,只要他们在更改输入之前至少等待五秒钟。此解决方案在轻触屏幕时忽略触摸屏设备上的鼠标指针模拟

var lastEvent=3;
var MOUSE_EVENT=1;
var TOUCH_事件=2;
元素。addEventListener('touchstart',函数(事件)
{
if(lastEvent==鼠标事件)
{
var time=Date.now()-eventTime;
如果(时间>5000)
{
eventTime=Date.now();
lastEvent=触摸事件;
交互启动(事件);
} 
}
其他的
{
lastEvent=触摸事件;
eventTime=Date.now();
交互启动(事件);
}
}) ;	
元素。addEventListener('mousedown',函数(事件)
{
如果(lastEvent==触摸事件)
{
var time=Date.now()-eventTime;
如果(时间>5000)
{
eventTime=Date.now();
lastEvent=鼠标事件;
交互启动(事件);
} 
}
其他的
{
lastEvent=鼠标事件;
eventTime=Date.now();
交互启动(事件);
}
}) ;  
函数interactionStart(事件)//在此处处理交互(触摸或单击)。

{…}
我发现了这个线程,因为我有一个类似的更复杂的问题:

假设我们创建了一个支持js的可滚动区域,其中包含下一个/上一个箭头,我们不仅希望对触摸和鼠标事件做出响应,还希望在用户继续按下屏幕或按住鼠标的同时重复触发它们

重复事件会使我的下一个按钮前进2个位置,而不是一个

在闭包的帮助下,一切似乎都是可能的:

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

 (function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
 * 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
}
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;
}
function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}
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);
};
myScroll.init = init;
(2)然后,从
setTimeout()

 (function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
 * 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
}
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;
}
function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}
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);
};
myScroll.init = init;
(4)附加事件处理程序:

 (function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
 * 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
}
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;
}
function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}
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);
};
myScroll.init = init;
触发事件
mousedown
touchstart
将对支持这两种功能的设备上的处理程序产生双重调用(可能首先触发触摸)。这同样适用于
mouseup
touchend

我们知道输入设备(实际上是整个图形环境)会按顺序生成事件,因此我们不关心先触发哪个事件,只要在private
eventLock.next.primary
eventLock.previous.primary
中为从处理程序捕获的第一个事件设置了
next*()
上一代*()

键是事件类型,因此第二个、第三个等事件始终是失败者,它们不会借助锁函数
eventLock()
primaryEventLock()
获得锁

(5)在事件处理程序的定义中可以看到上述内容:

 (function(myScroll, $, window, document, undefined){
 ...
 }(window.myScroll = window.myScroll || {}, jQuery, window, document));
/*
 * 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
}
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;
}
function init(){
   $('sth').off('mousedown touchstart', previousStart).on('mousedown touchstart', previousStart);
   $('sth').off('mouseup touchend', previousEnd).on('mouseup touchend', previousEnd);
   // similar for 'next*' handlers
}
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);
};
myScroll.init = init;
nextStart
nextEnd
类似

这个想法是,在第一次(触摸或鼠标)之后出现的任何人都不会在
函数eventLock(evt,key)
的帮助下获得,而是停在那里

打开此锁的唯一方法是在步骤(4):
previousEnd
nextEnd
中启动事件处理程序
*End()

我还处理了一个非常聪明的方式在会话中间附加的触摸设备问题:我注意到一个连续的按压时间比默认值。Press延迟> /CODE产生了回调函数的连续调用<强> >仅< /强>。(原因是没有结束事件处理程序终止callabck)

我定义了用户正在使用的设备,因此,您只需长按,然后您的设备立即变为主设备