输入触发按键事件两次

26
这个问题之前已经被问过/回答过(基本上),但是我尝试了三件事来阻止事件冒泡,但什么都没用:
return false;
e.stopPropagation();
e.preventDefault();  
(return false should take care of the other two, correct?)
这里是HTML代码:
<div class="tags-holder">
    <input type="text" class="addField" id="addField_<%= visit.id %>"  placeholder="add a new tag">
</div>

而且JS(更新已清理):

    $('.addField').show().keyup(function(event){
  event.preventDefault();
  
      if(event.keyCode == 13 || event.keyCode==9) {
    ProfilePage.createTag( this, 'nada', 'addField')
        $(this).hide().val('');

        return false;       
   }

我把多余的阻止器留在那里了,但真的不应该只是返回false就停止冒泡吗?(在Chrome中使用)。

线索?keyCode=13代表“Enter”键。


你为什么要使用 $(field).functionCall() 而不是 field.functionCall() - Yes Barry
1
我创建了一个jsFiddle来运行你的代码,没有发现任何问题 - 你想要避免什么样的行为? - topek
谢谢。那个有效;也许是由于事件冒泡在DOM中的原因(我没有发布整个页面)。问题在于它会两次触发createTag()函数,这是有问题的 :) - bear
我认为这根本不是冒泡。我认为你有一个带有.addField类的嵌套元素。这可能会导致你将函数分配给两个不同的嵌套元素...从而看起来像是冒泡——但实际上并不是。 - mqsoh
谢谢@mqsoh,我会检查一下。 - bear
显示剩余13条评论
9个回答

11

我曾经遇到同样的问题,我使用了上述方法,它对我有效。

$(document).unbind('keypress').bind('keypress', function (e) {
   // some logic here
});

11

哇,你的帮助非常棒,帮助我理清了思路。

但是解决方案感觉有点像是应急措施;虽然有效,但本来就不该有这个条件。

这里是我在评论中找到的解决方法: http://yuji.wordpress.com/2010/02/22/jquery-click-event-fires-twice/

    $('.plus').unbind('click').bind('click',function(e){    
console.log('clicked')
    var id=$(this).attr('plus_id');
    var field=$('<input type="text">').attr({'placeholder':'add a new tag','id': 'addField_' + id, 'visit_id':id});
    field.focus();
    field.show().keydown(function(event){
        event.stopImmediatePropagation();
        if(event.keyCode == 13 || event.keyCode==9) {
            console.log(event)
            ProfilePage.createTag( field, 'nada', 'addField')
            field.hide().val('');
            return false;       
        }
    }).click(function(e){
        return false;
    })
    ;
$(this).append(field);
return false;       
   });

哦,奇怪。现在它对你起作用了吗?如果是这样,那太好了!但根据你发布的那篇文章,似乎问题出在有多个$(document).ready()函数上。这是怎么回事? - Yes Barry
1
顺便提一下,我对此进行了更多的阅读,似乎这是设置keyup事件处理程序时的特定问题。 建议使用_keypress_处理程序...https://dev59.com/7nE95IYBdhLWcg3wQ7qc - Yes Barry
我会去检查一下 @mmmshuddup,但我认为这个问题非常特定于该项目;事实证明页面上的所有内容都在触发额外的事件。 - bear
@mmmshuddup,我在这里发布的内容是有效的。但事实证明,另一个函数引入了额外的内容,导致出现了问题。解除事件绑定可以解决问题,但在我看来,更好的实现方式不应该需要这样做。感谢您的帮助! - bear
7
对我来说,event.stopImmediatePropagation();是使jQuery停止调用处理程序两次的关键。 - Joshua Dwire
这里提供了一个关于.stopImmediatePropagation()和return false的好解释...https://dev59.com/SW435IYBdhLWcg3wohpT - nipiv

7

先尝试解绑事件,然后再绑定它,请参考下面的代码:

$('.addField').show().unbind('keyup').keyup(function(event){
 event.preventDefault();

  if(event.keyCode == 13 || event.keyCode==9) {
ProfilePage.createTag( this, 'nada', 'addField')
    $(this).hide().val('');

    return false;       
}

这里有一个解释点击此处,我在我的新博客上写了一篇文章。

博客文章链接已损坏。 - dfrankow

1
希望这能解决你的问题。 不要使用event.preventDefault(),而是使用下面两个中的一个。 对于Microsoft浏览器,请使用 event.cancelBubble = true; 对于W3C模型浏览器,请使用 event.stopPropagation();
并且请使用keypress事件代替keyup事件,因为在keypress事件中输入将被发送到输入字段,所以任何你不想出现的输入都会出现在字段中。因此,回车按钮事件将被触发。
请使用event.returnValue = false,而不是return false。

0
我在使用 Angular 11 中的 EventEmitters 时遇到了这个问题。我通过在每次触发事件时创建新的事件发射器实例来解决它。
@Output() keypress = new EventEmitter();
onKeyPress(event) {
   this.keypress = new EventEmitter();
   this.keypress.emit(event);
 }

0

我也经历过同样的问题,以下结构对我有用:

const onKeyPress = (e: React.KeyboardEvent): void => {
    if (onSubmit && e.key.toLowerCase() === 'enter') {
      onSubmit();

      e.stopPropagation();
      e.preventDefault();
    }
};

0
尝试更改所有的

实例。
$(field).functionCall() 

field.functionCall() 

由于field已经是一个jQuery对象。

好的,现在我们已经确定这不是错误。我在Firefox 7和Chrome 15中进行了测试,并发现当按下enter键时,if语句中的代码块只会被触发一次。尝试检查createTag()函数内部是否有重复执行的操作。


坏习惯......jQuery忽略了它,但我已经做出了更改,但没有改进。 - bear
该死。是的,承认吧,那个确实是一次碰运气。嗯,让我想一下这个问题片刻。 - Yes Barry
@user508708 我在 topek 创建的那个 jsFiddle 中为 createTag() 编写了一个模拟函数。警报仅触发一次。此时,如果不知道 DOM 中确切的内容以及 ProfilePage 对象引用的是什么,很难确定。 - Yes Barry
我认为你是对的。页面非常动态,完整地发布可能不切实际。我会开始缩小范围,看看能否找到问题所在。不过,我很惊讶我们不能直接杀死冒泡...哦,还有一个线索:我是在$(document).ready(function()中初始化的。 - bear

0
你认为在事件冒泡时捕获它是什么?使用这个测试页面,我只能得到一个触发。
<!DOCTYPE html>
<html>
  <head>
    <title>Scratch</title>
    <script type="text/javascript" src="https://www.google.com/jsapi"></script>
    <script type="text/javascript">
      google.setOnLoadCallback(function (){
        $('input[type="text"]').keyup(function (){
          console.debug('keyup');
        });
      });
      google.load('jquery', '1.6.4');
    </script>
  </head>
  <body>

    <div class="something">
      <input type="text" />
    </div>
  </body>
</html>

也许是你的选择器有问题。它是否嵌套在另一个 .addTag 中?当我改变 jQuery 选择器并且将 div 和 input 设为相同的类时,开始触发两个事件。就像这样:
$('.thing').show().keyup(...);

...而且...

<div class="thing">
    <input class="thing" type="text" />
</div>

0

这是一个经常让我发疯的问题,但我认为这就是解决方案:如果你返回true,它会随机重复自己,所以简单地返回false。我猜测它必须有一个监听器来监听true响应。

简短回答:添加return false;

$("#register-form #first_name").keyup(function(event) {
console.log('hello world');
return false;

});

在原问题中,如果你仔细看代码,似乎 return false 写得有点早了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接