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

问题描述 投票:0回答:5
element.on('click focus', function (e) {
    // Do Something
}

在我的示例中,do something 将运行两次。我希望每次交互只运行一次。

我正在使用焦点,因此用户可以进入元素以触发事件或单击它以触发事件。

如果用户多次与之交互(打开,然后关闭,然后再次打开),则可以多次触发该事件。

javascript jquery jquery-events
5个回答
1
投票

我的想法是这种行为是错误的,但是从您在这里的描述来看,这是处理您为菜单详细说明的事件的一般想法。在这里工作演示:https://jsfiddle.net/mcso7q1y/

HTML:

<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>

j查询:

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

0
投票

您可以滚动自己的方法来处理多个事件,使用轻微的超时来限制事件,因此只会触发一个事件等。

$.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))
  });
}

$.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))
  });
}

/* To be used like */

var element = $('a'), i = 0;

element.onMulti('click focus', function(e) {
  console.log('works : ' + (++i));
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<a href="#">Active Element Anchor, fires events on click and focus</a>
<br />
<br />
<br />
<div>Element to click on to remove focus</div>


0
投票

创建一个名为

done
的变量,如果
false
done
并且在函数结束时将
false
更改为
done
如果函数 get 再次触发 'Do Something' 将不会被执行,因为 'done' 设置为
true

true



-1
投票

var done = false; element.on('click focus', function (e) { if( !done ) { // Do Something } done = !done; }
$(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;
}

您可能想考虑编写一个 jQuery 插件而不是所有这些插件(或使用许多现有插件之一)。


-1
投票
更新的答案(2023)

如果您使用 addEventListener()
而不是 <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>,您可以像这样在纯 JavaScript 中执行此操作:

.on(event, fn)

解释:

当一个元素被点击或获得焦点时,第一个被触发的事件是 // 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
事件。使用
Event.stopImmediatePropagation()
我们中断传播,因此一次只会调用一个事件处理程序。 您体验到的双重输出来自

click

propagated
event事件到
focus
事件处理程序。
使用上述实现,您可以使用 

click

click
事件,这无关紧要。
    

© www.soinside.com 2019 - 2024. All rights reserved.