防止一个函数被多个事件同时调用
Prevent a function from being called by multiple events at the same time
element.on('click focus', function (e) {
// Do Something
}
在我的示例中,做某事将 运行 两次。我希望每次互动 运行 一次。
我正在使用焦点,因此用户可以切换到元素以触发事件或单击它以触发事件。
如果用户多次与之交互(打开、关闭、然后再次打开),则可以多次触发该事件。
创建一个名为 done
的变量并将其设置为 false
当仅触发函数时 'Do Something' 如果 done
为 false
并更改 done
到 true
在函数的末尾,所以如果函数再次被触发 'Do Something' 将不会被执行,因为 'done' 被设置为 true
var done = false;
element.on('click focus', function (e) {
if( !done ) {
// Do Something
}
done = !done;
}
我的想法是这种行为是错误的,但根据您在此处的描述,可以大致了解如何处理您为菜单详细说明的事件。在这里工作演示: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>
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();
}
}
您可以推出自己的方法来处理多个事件,使用轻微的超时来限制事件,因此只会触发一个事件等。
$.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>
我建议在这里采取不同的策略。与其处理全局变量之类的,不如跟踪菜单的状态,并在必要时进行切换。
$(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 插件而不是全部(或使用许多现有插件之一)。
element.on('click focus', function (e) {
// Do Something
}
在我的示例中,做某事将 运行 两次。我希望每次互动 运行 一次。
我正在使用焦点,因此用户可以切换到元素以触发事件或单击它以触发事件。
如果用户多次与之交互(打开、关闭、然后再次打开),则可以多次触发该事件。
创建一个名为 done
的变量并将其设置为 false
当仅触发函数时 'Do Something' 如果 done
为 false
并更改 done
到 true
在函数的末尾,所以如果函数再次被触发 'Do Something' 将不会被执行,因为 'done' 被设置为 true
var done = false;
element.on('click focus', function (e) {
if( !done ) {
// Do Something
}
done = !done;
}
我的想法是这种行为是错误的,但根据您在此处的描述,可以大致了解如何处理您为菜单详细说明的事件。在这里工作演示: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>
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();
}
}
您可以推出自己的方法来处理多个事件,使用轻微的超时来限制事件,因此只会触发一个事件等。
$.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>
我建议在这里采取不同的策略。与其处理全局变量之类的,不如跟踪菜单的状态,并在必要时进行切换。
$(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 插件而不是全部(或使用许多现有插件之一)。