为什么onclick会被触发两次?

6

我一直在研究的是以下这段小代码:

我的目标是在单击相同元素时向标签添加active类,并保持默认行为不变。

我不知道为什么单击事件会触发两次??

$('label.add-to-favourite').click(function(e){
  alert("here");
  $(this).toggleClass('active');
});
.add-to-favourite span{
    cursor: pointer;
    color: #d2d6de;
}


.add-to-favourite:hover span, .add-to-favourite.active span {
    color: #CB3D3D;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>

<ul>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" name="favourites[]" value="1">
    </label>
  </li>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" name="favourites[]" value="2">
    </label>
  </li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


关于此行为,请参见规范:例如,在点击复选框标签检查复选框的平台上,单击以下代码片段中的标签可能会触发用户代理运行合成点击激活步骤的输入元素,就像元素本身已被用户触发一样:<label><input type=checkbox name=lost> Lost</label> 在其他平台上,行为可能仅是将控件聚焦或不执行任何操作。 - A. Wolff
7个回答

5
当您点击标签时,它会触发复选框的点击事件。但是,点击标签还会自动发送一个单击事件到相关联的输入元素,因此这被视为对复选框的单击。然后,事件冒泡导致该单击事件在包含元素(即标签)上触发,因此您的处理程序再次运行。
请将复选框放在标签外部,如下所示。
<label></label>
<input type="checkbox">

更新:您也可以像@Rejith R Krishnan建议的那样,在复选框上设置点击事件处理程序而不是标签


与其重新定位复选框(如果按照您所示的方式进行,会破坏它们之间的可访问性连接),我建议只需更改OP侦听“click”的元素即可。 - T.J. Crowder
好的,我明白了。但是有没有一种方法可以在不更改HTML的情况下实现这个? - Mohan
是的,您可以像@Rejith R Krishnan建议的那样,在复选框上设置单击事件。 - WalksAway
1
@AngryCoder:是的:监听复选框上的“点击”事件,而不是标签。 - T.J. Crowder
实际上,Rejith建议使用change。现在它可能非常可靠地工作了。(许多年前,在一些浏览器上,直到焦点离开复选框才会触发它,但现在应该没有问题了...) - T.J. Crowder
显示剩余3条评论

4

只需定义目标元素类型,这个就能很好地工作。

$('label.add-to-favourite').click(function(e){

 if(e.target.type=='checkbox'){
     alert("here");
     $(this).toggleClass('active');
   }

});
.add-to-favourite span{
    cursor: pointer;
    color: #d2d6de;
}


.add-to-favourite:hover span, .add-to-favourite.active span {
    color: #CB3D3D;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>

<ul>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" name="favourites[]" value="1">
    </label>
  </li>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" name="favourites[]" value="2">
    </label>
  </li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


1
您可以尝试这段代码:

$('label.add-to-favourite').click(function(e){
    e.preventDefault();
    var $check = $(':checkbox', this);
    $check.prop('checked', !$check.prop('checked'));
    alert("here");
    $(this).toggleClass('active');
});

它将添加类并检查复选框。
示例:https://jsfiddle.net/Mindaugas/71sefdhp/

0

移除点击事件的绑定,改为将 change 事件绑定到 checkbox 上。

$('label.add-to-favourite :checkbox').change(function(e){
  alert("here");
  $(this).toggleClass('active');
});
.add-to-favourite span{
    cursor: pointer;
    color: #d2d6de;
}
.add-to-favourite:hover span, .add-to-favourite.active span {
    color: #CB3D3D;
}
.hide{display:none;}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet"/>

<ul>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" class="hide" name="favourites[]" value="1">
    </label>
  </li>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
      <input type="checkbox" class="hide" name="favourites[]" value="2">
    </label>
  </li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


0
我不知道为什么点击事件会被触发两次??
嗯,我想说label元素是checkbox的父元素,所以它们之间有联系。当你点击标签时,点击也会发生在复选框上,并且事件会冒泡,因此会导致两个警报。
要么将复选框从标签中取出,要么只能通过CSS实现相同的效果。
以下是一个结构稍微改变的示例。

$('label.add-to-favourite').click(function(e) {
  alert("here");
  $(this).toggleClass('active').siblings(':checkbox').prop('checked', $(this).hasClass('active'))
});
.add-to-favourite span {
  cursor: pointer;
  color: #d2d6de;
}
.add-to-favourite:hover span,
.add-to-favourite.active span {
  color: #CB3D3D;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />

<ul>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
    </label>
    <input type="checkbox" name="favourites[]" value="1">

  </li>
  <li>
    <label class="add-to-favourite">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
    </label>
    <input type="checkbox" name="favourites[]" value="2">

  </li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

一个仅使用CSS的解决方案。

li{overflow:auto;}
.add-to-favourite span {
  cursor: pointer;
  color: #d2d6de;
  float:left;
}
.add-to-favourite input[type="checkbox"]{
    margin-top:15px;
}
.add-to-favourite:hover span,
.add-to-favourite input[type="checkbox"]:checked + span{
  color: #CB3D3D;
}
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.6.3/css/font-awesome.min.css" rel="stylesheet" />

<ul>
  <li>
    <label class="add-to-favourite">
      <input type="checkbox" name="favourites[]" value="1">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
    </label>
  </li>
  <li>
    <label class="add-to-favourite">
      <input type="checkbox" name="favourites[]" value="2">
      <span class="fa-stack fa-lg">
          <i class="fa fa-circle fa-stack-2x"></i>
          <i class="fa fa-heart fa-stack-1x fa-inverse"  title="Add to Favourites" data-toggle="tooltip"></i>
      </span>
    </label>
  </li>
</ul>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>


0

这是事件传播的情况。试试看

$('label.add-to-favourite').click(function(e){
  alert("here");
  $(this).toggleClass('active');
 e.preventDefault();
});

我已经尝试过这个了。这将阻止元素的默认行为,复选框不会被选中。 - Mohan

-2

同时移除警告。

$('label.add-to-favourite').on("click",function(e){
  $(this).toggleClass('active');
});

1
我添加了警告,只是为了显示事件被触发两次。 - Mohan

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