繁体   English   中英

当一个函数同时被焦点和点击事件触发时,如何只运行一次

[英]How to run a function only once when it's triggered by both focus and click events

我有一个带有 2 个事件的输入元素:焦点和单击。 它们都触发相同的辅助函数。

当我选择输入时,焦点事件会触发并且我的助手运行一次。 没有问题。

当元素已经获得焦点时,我再次单击它,单击事件会触发并且我的助手运行一次。 那里也没有问题。

但是当元素没有焦点时,我点击它,两个事件都会触发,我的助手运行两次。 我怎样才能让这个助手只运行一次?

我在这里看到了几个类似的问题,但并没有真正遵循他们的答案。 我还发现了 .live jQuery 处理程序,如果我让它监视状态类,它似乎可以工作。 但似乎应该有一个更简单的方法。 .one 处理程序可以工作,除非我需要它多次工作。

谢谢你的帮助!

这里最好的答案是提出一个设计,它不会试图在两个不同的事件上触发相同的操作,而这两个不同的事件都可能发生在同一个用户操作上,但是由于您还没有真正解释整个问题编码,我们无法真正帮助您使用这种方法。

一种方法是防止单个事件两次触发相同的事情是“去抖动”函数调用,并且仅在给定元素最近没有被调用的情况下才从给定元素调用该函数(例如,可能来自同一个用户事件)。 您可以通过记录此元素上次触发的时间来实现此目的,并且仅当时间长于某个值时才调用该函数。

这是您可以做到的一种方法:

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

您可以使用已清除和设置的超时。 这会引入一个轻微的延迟,但确保只触发最后一个事件。

$(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的评论,您可以使doubleBounceTimeout成为超时的集合,并在事件处理程序中传递一个键。 或者您可以将相同的超时传递给处理相同事件的任何方法。 通过这种方式,您可以使用相同的方法来处理任意数量的输入。

这对我有用:

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

我直接从这里偷的: https : //stackoverflow.com/a/9440580/264498

在我看来,您实际上并不需要点击处理程序。 听起来这个事件附加到一个元素上,该元素在单击时获得焦点并触发焦点处理程序。 所以点击它总是会触发你的焦点处理程序,所以你只需要焦点处理程序。

如果情况并非如此,那么不幸的是,没有简单的方法可以实现您的要求。 在焦点上添加/删除类并仅在类不存在时触发单击是我能想到的唯一方法。

我有 - 2 个选项

1 - 将点击处理程序绑定到焦点回调中的元素

2 - 将焦点和点击处理程序绑定到不同的类,并使用焦点回调添加点击类并使用模糊移除点击类

现场演示(点击)。

我只是简单地设置一个标志来在第一次单击元素时关闭单击(给定焦点)。 然后,如果元素从 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;
    }
  }
});

感谢大家的精彩讨论。 似乎来自@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');
});

但似乎其他人稍微优雅一些​​。 我特别喜欢克里斯的,因为它不涉及时间问题。

再次感谢!!

改进@Christopher Meyers 解决方案。

一些介绍:在 click 事件触发之前,有 2 个事件在它之前,mousedown 和 mouseup,如果 mousedown 被触发,我们知道 mouseup 可能会触发。 因此,我们可能不希望焦点事件处理程序执行其操作。 mouseup 不会触发的一种情况是,如果用户开始单击按钮然后将光标拖走,为此我们使用了 blur 事件。

  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 }
];

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM