我有一个输入元素,附加了2个事件:焦点和单击。他们都启动了相同的辅助功能。
当我选择输入时,焦点事件将触发,我的助手将运行一次。没问题。
当元素已经有焦点,然后我再次点击它时,click事件会触发,我的助手会运行一次。那里也没问题。
但是当元素没有焦点时,我点击它,两个事件都会触发,我的助手会运行TWICE。如何让这个助手只运行一次?
我在这里看到了几个类似的问题,但并没有真正按照他们的答案。我还发现了.live jQuery处理程序,如果我让它看一个状态类,它似乎可以工作。但似乎应该有一个更简单的方法。 .one处理程序可以工作,除了我需要多次工作。
感谢您的帮助!
答案 0 :(得分:7)
这里最好的答案是想出一个设计,它不会尝试在同一个用户操作上发生的两个不同事件上触发相同的操作,但是因为你还没有真正解释整个问题你正在编码,我们无法真正帮助你采用这种方法。
一种方法是保持单个事件两次触发相同的事情是“去抖”函数调用,并且如果最近没有调用它,则仅从给定元素调用该函数(例如,可能来自同一用户)事件)。您可以通过记录此元素的最后一次触发的时间来执行此操作,并且只有在时间长于某个值时才调用该函数。
这是你可以做到的一种方式:
function debounceMyFunction() {
var now = new Date().getTime();
var prevTime = $(this).data("prevActionTime");
$(this).data("prevActionTime", now);
// only call my function if we haven't just called it (within the last second)
if (!prevTime || now - prevTime > 1000) {
callMyFunction();
}
}
$(elem).focus(debounceMyFunction).click(debounceMyFunction);
答案 1 :(得分:3)
这对我有用:
http://jsfiddle.net/cjmemay/zN8Ns/1/
$('.button').on('mousedown', function(){
$(this).data("mouseDown", true);
});
$('.button').on('mouseup', function(){
$(this).removeData("mouseDown");
});
$('.button').on('focus', function(){
if (!$(this).data("mouseDown"))
$(this).trigger('click.click');
});
$(".button").on('click.click',evHandler);
答案 2 :(得分:1)
在我看来,您实际上并不需要点击处理程序。听起来这个事件被附加到一个元素上,当点击它时会获得焦点并激活焦点处理程序。因此,单击它总是会激活您的焦点处理程序,因此您只需要焦点处理程序。
如果情况并非如此,那么不幸的是,没有简单的方法来实现您的要求。在焦点上添加/删除一个类,并且只在该类不存在时触发单击是我能想到的唯一方法。
我有它 - 2个选项
1 - 将单击处理程序绑定到焦点回调
中的元素2 - 将焦点和点击处理程序绑定到另一个类,并使用焦点回调添加点击类并使用模糊删除点击类
答案 3 :(得分:1)
<强> Live demo (click). 强>
我只是设置一个标志来在第一次点击元素时关闭点击(给定焦点)。然后,如果元素从Tab键获得焦点,则该标志也将被删除,以便第一次单击将起作用。
var $foo = $('#foo');
var flag = 0;
$foo.click(function() {
if (flag) {
flag = 0;
return false;
}
console.log('clicked');
});
$foo.focus(function() {
flag = 1;
console.log('focused');
});
$(document).keyup(function(e) {
if (e.which === 9) {
var $focused = $('input:focus');
if ($focused.is($foo)) {
flag = 0;
}
}
});
答案 4 :(得分:1)
您可以使用已清除并设置的超时。这会引入一些延迟,但只能确保触发最后一个事件。
$(function() {
$('#field').on('click focus', function() {
debounce(function() {
// Your code goes here.
console.log('event');
});
});
});
var debounceTimeout;
function debounce(callback) {
clearTimeout(debounceTimeout);
debounceTimeout = setTimeout(callback, 500);
}
这是小提琴http://jsfiddle.net/APEdu/
<强>更新强>
要在别处处理有关全局使用的注释,可以使用事件处理程序中传递的键使doubleBounceTimeout
超时集合。或者您可以将相同的超时传递给处理相同事件的任何方法。这样,您可以使用相同的方法处理任意数量的输入。
答案 5 :(得分:0)
感谢大家的热烈讨论。似乎来自@ jfriend00的debouncing解决方案,以及Chris Meyers的mousedown解决方案,都是处理它的好方法。
我想了更多,并提出了这个解决方案:
// add focus event
$myInput.focus(function() {
myHelper();
// while focus is active, add click event
setTimeout(function() {
$myInput.click(function() {
myHelper();
});
}, 500); // slight delay seems to be required
});
// when we lose focus, unbind click event
$myInput.blur(function() {
$myInput.off('click');
});
但似乎其他人稍微优雅一点。我特别喜欢克里斯,因为它不涉及处理时间。
再次感谢!!
答案 6 :(得分:0)
改进@Christopher Meyers解决方案。
一些介绍:单击事件触发之前,将先触发2个事件,mousedown和mouseup,如果触发了mousedown,我们知道可能会触发mouseup。 因此,我们可能不希望焦点事件处理程序执行其操作。一种不触发mouseup的情况是,如果用户开始单击按钮,然后将光标拖走,为此我们使用了模糊事件。
let mousedown = false;
const onMousedown = () => {
mousedown = true;
};
const onMouseup = () => {
mousedown = false;
// perform action
};
const onFocus = () => {
if (mousedown) return;
// perform action
};
const onBlur = () => {
mousedown = false;
// perform action if wanted
};
将附加以下事件:
const events = [
{ type: 'focus', handler: onFocus },
{ type: 'blur', handler: onBlur },
{ type: 'mousedown', handler: onMousedown },
{ type: 'mouseup', handler: onMouseup }
];