清除 JavaScript/jQuery 事件队列

Clearing the JavaScript/jQuery Event Queue

我们发现,在最近升级到 Google Chrome(版本 55+)期间,引入了 pointer events "with a newer standard that unifies both models: pointer events.",我们需要修改我们处理事件的方式以向后兼容。我们的应用程序是专门为 Chrome.

编写的

我们今天早上 experimenting 试图找出触发了哪个事件(基于 Chrome 版本),以便我们可以为所有应用程序用户适当地处理该事件。作为测试,我写了以下内容:

$(document).on('mousedown touchstart pointerdown', '.foo', function(event){
    console.log( event.type + ": " +  event.which );
    switch(event.type) {
        case 'mousedown':
          console.log('moused!');
          break;
        case 'touchstart':
          console.log('touched!');
          break;
        case 'pointerdown':
          console.log('pointed');
          break;    
    };
})

在非移动设备中,mousedownpointerdown 均已注册。在移动设备中,所有三个事件都被输出到控制台。

澄清:需要的是 none 其他事件在遇到并处理第一个事件后触发。换句话说,例如,如果 pointerdown 触发,那么我需要阻止 mousedowntouchstart 触发。随后的点击也应该有效,所以如果我得到一个 pointerdown 并再次点击我应该得到另一个 pointerdown (或者任何适合浏览器版本或设备的事件)。

我预计 break; 会导致 jQuery 离开 switch(),但这并没有发生。所以我在每个案例中添加了 .clearQueue()

$(this).clearQueue();

再一次,我预计会遇到并处理事件,队列会被清除,我不会触发任何其他事件。

我错了

我开始觉得我遗漏了一些明显的东西,但我无法确定。我已经尝试 .stop(), .finish() 以及这些函数的组合,以拦截所需的一个函数(基于浏览器版本)并清除队列,这样其余的就不会触发。

我以为我很了解 JavaScript 事件队列,但显然我也错了。

我是不是遗漏了什么明显的东西?如果是这样,它是什么?

我认为 .stop().finish() 与使用动画队列有关,而不是事件队列,并且 .clearQueue() 也与事件队列无关:

JQuery documentation 说:

When used without an argument, .clearQueue() removes the remaining functions from fx, the standard effects queue. In this way it is similar to .stop(true). However, while the .stop() method is meant to be used only with animations, .clearQueue() can also be used to remove any function that has been added to a generic jQuery queue with the .queue() method.

但是,如果您处理了一个事件并希望阻止其他事件被引发,您可以在闭包中实现自己的 handled 标志作为变通方法:

这里有一个例子(可执行版本here):

// These free variables will be shared in the various callback functions below
var handled = false;
var eventType = null;

$(document).on('mousedown touchstart pointerdown', '.foo', function(event){

   // If the current event hasn't been handled or if the current 
   // has been handled but the event is the same as the previous fired 
   // event, proceed:
   if(!handled || (handled && event.type === eventType)){

     // None of the events have been handled yet.
     // Determine which has fired and act appropriately:

     // Register the current event for comparison later
     eventType = event.type;

     console.log( eventType + ": " +  event.which );

     switch(eventType) {
        case 'mousedown':
          console.log('moused!');
          break;
        case 'touchstart':
          console.log('touched!');
          break;
        case 'pointerdown':
          console.log('pointed');
          break;    
     };

     // Flag that one of the events registered earlier has been handled
     handled = true;

   } else {

     // One of the earlier registered events has already been handled

     // Prevent the event from performing its native function
     // (i.e. cancel the event)
     event.preventDefault();

     // Don't allow the event to propagate
     event.stopPropagation();

   }

});

你可以在最后 return false,只有第一个支持的类型(和第一个触发的)会被任何系统捕获。

break 工作正常,但它不会影响此问题,因为这些是不同的事件,因此触发处理程序的次数与事件触发的次数一样多。

$(document).on('mousedown touchstart pointerdown', '.foo', function(event){
    console.log( event.type + ": " +  event.which );
    switch(event.type) {
        case 'mousedown':
          console.log('moused!');
          break;
        case 'touchstart':
          console.log('touched!');
          break;
        case 'pointerdown':
          console.log('pointed');
          break;    
    };
    // added the following line which forces any subsequent events for the same action and also stop the event from bubbling up the dom
    return false;
})
.foo{
  padding:50px;
  margin:10px;
  border:5px double #ccc;
  text-align:center;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="foo">.foo box for clicking</div>