jquery 防止函数同时被多个事件调用

uhry853o  于 2023-03-07  发布在  jQuery
关注(0)|答案(5)|浏览(137)
element.on('click focus', function (e) {
    // Do Something
}

在我的例子中,do something将运行两次,我希望它在每次交互中只运行一次。
我使用了焦点,这样用户就可以通过Tab键进入元素来触发事件,或者单击元素来触发事件。
如果用户与事件进行多次交互(选项卡打开,然后关闭,然后再次打开),则可以多次激发该事件。

eimct9ow

eimct9ow1#

我认为这种行为是错误的,但从您的描述来看,这里是处理您为菜单详细描述的事件的一般思路。https://jsfiddle.net/mcso7q1y/
超文本:

<button id="btn">Click Me</button>

<ul id="menu">
     <li>This is a menu.</li>
     <li>This is a menu.</li>
     <li>This is a menu.</li>
     <li>This is a menu.</li>
</ul>

jQuery:

$(document).ready(function(){
    $("#menu").slideUp("fast");
    var closed = true;

    $("#btn").click(function(){                       
          menuToggle(closed);
          closed = !closed;
    });

    $("#btn").focus(function(){
         menuToggle(closed);
         closed = !closed;
    });

    $("#btn").focusout(function(){
         menuToggle(closed);
         closed = !closed;
    });
});

function menuToggle(clsd){
    if(clsd){ 
        $("#menu").slideDown();          
    } else {
        $("#menu").slideUp();          
    }
}
guz6ccqo

guz6ccqo2#

你可以滚动你自己的方法来处理多个事件,使用一个小的超时来限制事件,这样只有一个事件会被触发。

$.fn.onMulti = function() {
  var temp = [].slice.call(arguments), fn = temp.pop();

  return this.on(...temp, function() {
    clearTimeout($(this).data('multiTimer'));
    $(this).data('multiTimer', setTimeout(fn.bind(this, arguments), 200))
  });
}

x一个一个一个一个x一个一个二个x

ngynwnxp

ngynwnxp3#

创建一个名为done的变量,并在函数被触发时将其设置为false,如果donefalse,则仅“Do Something”,并在函数结束时将done更改为true,以便在函数再次被触发时,不会执行“Do Something”,因为“done”被设置为true

var done = false;

element.on('click focus', function (e) {
    if( !done ) {
        // Do Something
    }

    done = !done;
}
uxh89sit

uxh89sit4#

在这里我建议一个不同的策略。与其处理全局变量和所有这些,不如跟踪菜单的状态,并在必要时进行切换。

$(function() {
  function Menu(element) {
    this.isOpen = false;
    this.element = element;
    $(this.element).on('focusin', this.open.bind(this));
    $(this.element).on('focusout', this.close.bind(this));
    $(this.element).on('click', this.open.bind(this));
  }
  Menu.prototype.open = function() {
    this.isOpen = true;
    this.update();
  }
  Menu.prototype.close = function() {
    this.isOpen = false;
    this.update();
  }
  Menu.prototype.update = function() {
    $(this.element).toggleClass('open', this.isOpen);
  }

  $('.item').each(function (ix, el) { new Menu(el); });

});
.item .submenu {
  display: none;
}

.item.open .submenu {
  display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
  <li class="item"><a href="#">Menu</a>
    <ul class="submenu">
      <li>Submenu</li>
      <li>Submenu</li>
    </ul>
  </li>
  <li class="item"><a href="#">Menu</a>
    <ul class="submenu">
      <li>Submenu</li>
      <li>Submenu</li>
    </ul>
  </li>
</ul>

您可能需要考虑编写一个jQuery插件来代替所有这些插件(或者使用许多现有插件中的一个)。

ivqmmu1c

ivqmmu1c5#

    • 更新答复(2023年)**

如果你使用addEventListener()而不是.on(event, fn),你可以在纯JavaScript中这样做:

// when element is clicked it triggers the 'focus' event before the 'click' event
element.addEventListener( 'focus', ( e ) => {  
    e.stopImmediatePropagation(); // stops event propagation
    // here goes the stuff you want to be executed once at a time
});
    • 说明:**

当一个元素被点击时,第一个被触发的事件是focus事件,然后传播到click事件。使用Event.stopImmediatePropagation(),我们中断传播,这样一次只调用一个事件处理程序。
您遇到的多个输出来自eventfocus事件 * 传播 * 到click事件处理程序。
你可以用这个来测试:

element.addEventListener( 'focus', ( e ) => clickFocusHandler( e, 'focus' ) );
element.addEventListener( 'click', ( e ) => clickFocusHandler( e, 'click' ) );

function clickFocusHandler( e, from ) {
    console.log( 'hello from:', from );
}

如果发生focus事件,此代码将输出:

hello from focus
hello from focus
...

当它是click事件时,它将输出:

hello from focus
hello from focus
...
hello from click
hello from click
...

如果在定义用于focus事件的侦听器之前定义click事件侦听器,则这些输出将保持不变。

  • 如果您在测试示例中使用event.stopImmediatePropagation(),则在触发focus事件时,它将抑制来自event * 传播 * 的多个输出。

但是,如果您在元素上定义了click事件侦听器,则在单击元素时将有双输出,因为将执行2个侦听器。**在这种情况下,**您可能希望取消该click侦听器或使用Event.preventDefault()Event.defaultPrevented * 属性 * 取消事件,以放弃该event的任何多代码执行。

  • 如果取消click事件侦听器,则在单击元素时仍会有focus输出。

所以最短的版本是在文章的顶部,如果你想用两个事件监听器和同一个处理方法,它将是这个较长的版本:

element.addEventListener( 'focus', ( e ) => clickFocusHandler( e ) );
element.addEventListener( 'click', ( e ) => clickFocusHandler( e ) );

function clickFocusHandler( e ) {
    e.stopImmediatePropagation();
    if ( e.defaultPrevented == false ) {
        e.preventDefault();
        // here goes the stuff you want to be executed once at a time
    }
}

相关问题