绑定到焦点上的输入并单击时,防止函数触发两次

时间:2013-07-08 16:37:06

标签: jquery binding

我正在尝试在clickfocus上触发事件,但我只想要触发一次。当我在输入内部单击时,它会触发两次(单击并聚焦)。我该如何防止这种情况?

$('input').on('focus click', function(){
    console.log('fired');
});

3 个答案:

答案 0 :(得分:10)

您可以改用.one。这只会允许事件触发一次,但也会在触发后删除绑定:

$('input').one('focus click', function(){
    console.log('fired');
});

如果您需要保留绑定,则必须跟踪鼠标按钮的状态以及触发mousedown的当前目标:

var mouseDown, currentTarget;
$('input').on({
    "mousedown mouseup": function (e) {
        mouseDown = e.type === "mousedown";
        currentTarget = e.target;
    },
    "focus click": function (e) {
        if (mouseDown && currentTarget === e.target) return;
        console.log('fired');
    }
});

请参阅test case on jsFiddle

答案 1 :(得分:8)

稍微滞后可能是一种选择。基本记录您最后一次响应任一事件并忽略保护时间内的后续事件。

可以使用jQuery的data(回答结束时的例子),但我更喜欢这个:一个通用的去抖者:

Live Example using click and focus | Live Source

$("#field").on("click focus", debounce(100, function(e) {
  // Event occurred, but not with 100ms of the previous one
}));

debouncer功能:

// debounce - debounces a function call
//
// Usage: var f = debounce([guardTime, ] func);
//
// Where `guardTime` is the interval during which to suppress
// repeated calls, and `func` in the function to call.
// You use the returned function instead of `func` to get
// debouncing;
//
// Example: Debouncing a jQuery `click` event so if it happens
// more than once within a second (1,000ms), subsequent ones
// are ignored:
//
//    $("selector").on("click", debounce(1000, function(e) {
//      // Click occurred, but not within 1000ms of previous
//    });
//
// Both `this` and arguments are passed through.
function debounce(guardTime, func) {
  var last = 0;

  if (typeof guardTime === "function") {
    func = guardTime;
    guardTime = 100;
  }
  if (!guardTime) {
    throw "No function given to debounce";
  }
  if (!func) {
    throw "No func given to debounce";
  }

  return function() {
    var now = +new Date();
    if (!last || (now - last) > guardTime) {
      last = now;
      return func.apply(this, arguments);
    }
  };
}

(“debouncer”这个名称是使用滞后来限速输入的常用术语.IIRC,它来自“开关去抖动器”,这是一个(非常)简单的电路,用于避免触发动作数百次由于机械投掷电开关从打开过渡到关闭,反之亦然,因为当触点接近时,在开关稳定之前可能会有很多关闭/打开/关闭/打开/关闭/打开颤动-state。这个聊天被称为“bouncing”,因此,“debouncer。”)


这种方法只使用jQuery的data

$('input').on('focus click', function(){
    var $this = $(this);
    var now = +new Date();
    var lastClicked = $this.data("lastClicked");
    if (lastClicked && (now - lastClicked) < 100) {
        // Don't do anything
        return;
    }
    $this.data("lastClicked", now);

    // Do the work
});

答案 2 :(得分:1)

这是一个老问题,但我找不到任何其他答案,比如什么解决了我的问题。因此,我会在2015年为所有碰巧遇到此问题的人发布此帖。

$('#menu-button').on('click focus', function() {
  if(!$(this).is(':focus')) { // 1
    // Do stuff once
  }
  else {
    $this.blur(); // 2
  }
});
  1. 仅在点击时触发事件。我不确定幕后会发生什么,所以也许有人可以向我解释这一点,但是标签和焦点似乎没有触及并且100%工作。

  2. 这会取消选中对象的焦点,但会将焦点路径设置回文档的顶部。我把它留在这里,所以我可以再次单击所选元素以禁用菜单。我仍然在寻找修复以保持焦点路径。

  3. 编辑:更好的方式:

    $('#menu-button').on('click focus', function(event) {
      if(event.type === 'focus') { // 1
        // Do stuff once
      }
    });
    
    1. 点击会触发焦点,但焦点不会触发点击。所以只需在焦点事件上运行代码。