清空JavaScript/jQuery事件队列

3
我们发现,在最近升级到Google Chrome(版本55+)时,引入了指针事件“使用新的标准统一了这两种模型:指针事件。”,我们需要修改事件处理方式以实现向后兼容。我们的应用程序是专门为Chrome编写的。
今天早上,我们一直在实验,试图确定触发了哪个事件(基于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都被注册。在移动设备上,所有三个事件都会被输出到控制台。 澄清:需要的是一旦遇到并处理第一个事件,就不再触发任何其他事件。换句话说,如果例如触发了pointerdown,则需要防止触发mousedowntouchstart。后续的点击也应该正常工作,所以如果我得到一个pointerdown并再次点击,则应该得到另一个pointerdown(或适用于浏览器版本或设备的其他事件)。
我原本期望break;会导致jQuery离开switch(),但事实并非如此。因此,我在每个case中添加了.clearQueue()
$(this).clearQueue();

再一次,我期望事件会被遇到和处理,队列会被清除,我就不会有其他事件触发了。

但我错了。

我开始感觉自己似乎漏掉了一些显而易见的东西,但我无法确定是什么。我已经尝试过 .stop().finish() 以及这些函数的组合,以便拦截所需的一个函数(基于浏览器版本)并清除队列,以便其余部分不会触发。

我认为我对JavaScript事件队列非常了解,但显然我也错了。

我是否漏掉了一些显而易见的东西?如果是这样,它是什么?

2个回答

3
我认为.stop().finish()与动画队列有关,而不是事件队列,.clearQueue()也与事件队列无关:
根据JQuery文档的说法:
当没有参数时,.clearQueue()会从fx(标准效果队列)中删除剩余的函数。在这方面,它类似于.stop(true)。然而,虽然.stop()方法只用于动画,但.clearQueue()也可以用于删除使用.queue()方法添加到通用jQuery队列中的任何函数。
但是,如果您已经处理了一个事件并希望阻止其他事件被触发,可以通过闭包实现自己的handled标志来解决问题:
这里有一个示例(可执行版本在这里):
// 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();

   }

});

1
JQuery抽象了标准的JavaScript和DOM API。当您使用queue()时,您正在注册自己的回调函数,但对于事件注册.on(....),不使用.queue() - Scott Marcus
1
好的 - 这解释了为什么 .clearQueue() 没有起作用。 - Jay Blanchard
1
不是这样的@SamBattat。快速测试表明它不起作用。它只停止每个事件的传播。它不会在处理例如“mousedown”之后停止其他事件。pointerdown仍然会触发。 - Jay Blanchard
谢谢Scott,我非常感激你在这里的努力。我的大脑已经变得很混乱了,因为我一直在尝试弄清楚该怎么做。 - Jay Blanchard
好的,请尝试最新版本。 - Scott Marcus
显示剩余9条评论

0

你可以在最后加上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>


这不会阻止其他已触发的事件继续触发。请参见:https://jsfiddle.net/61vt7t1w/3/,其中显示了这一点。在JQuery事件处理程序中使用`return false与使用event.preventDefault()event.stopPropagation()`是相同的,它们只能拦截一个事件。 - Scott Marcus
请查看我的解决方案以及它与你的方案有何不同:https://jsfiddle.net/qg5jxrsc/4/。 - Scott Marcus
@ScottMarcus,您正在测试不同类型的事件。OP正在寻求针对相同用户操作触发的事件,即mousedowntouchstartpointerdown - Gabriele Petrioli

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接