为什么onclick元素会为label元素触发两次

时间:2014-07-01 02:05:42

标签: javascript html



      window.onload = function(){
         var wow = document.getElementById("wow");
    	 wow.onclick = function(){
    	     alert("hi");
    	 }
      }

    <label id="wow"><input type="checkbox" name="checkbox" value="value">Text</label>
&#13;
&#13;
&#13;

这是我的代码,当我点击&#34; Text&#34;它会提示两次,但当我点击框时,onclick元素只会触发一次,为什么?

7 个答案:

答案 0 :(得分:45)

当您点击标签时,它会触发点击处理程序,然后您会收到提醒。

但是,单击标签也会自动向相关的输入元素发送单击事件,因此将其视为单击复选框。然后事件冒泡导致在包含元素(即标签)上触发click事件,因此您的处理程序将再次运行。

如果您将HTML更改为此,则无法获得双重警报:

<input id="wowcb" type="checkbox" name="checkbox" value="value">
<label id="wow" for="wowcb">Text</label>

现在,标签使用for属性与复选框相关联,而不是环绕它。

DEMO

答案 1 :(得分:3)

如果您的目的是仅响应标签上的点击而不是复选框,则可以查看 event.target 属性。它引用了调用侦听器的元素,以便如果单击不在该元素上,则不要执行该操作:

window.onload = function(){
  var el = document.getElementById('wow');
  el.addEventListener('click', function(event) {

    if (this === event.target) {
      /* click was on label */
      alert('click was on label');

    } else {
      /* click was on checkbox */
      event.stopPropagation();
      return false;
    }

  }, false);
}

另一方面,如果您只想响应复选框上的点击(标签上的点击也会勾选复选框),则执行相反的操作。对标签上的点击不做任何操作,并从复选框中选择:

window.onload = function(){
  var el = document.getElementById('foolabel');
  el.addEventListener('click', function(event) {

    if (this === event.target) {
      /* click was on label */
      event.stopPropagation();
      return false;

    } else {

      /*
      ** click is from checkbox, initiated by click on label
      ** or checkbox                                  
      */

      alert('click from checkbox');
    }

  }, false);
}

这个版本似乎有最自然的行为。但是,更改标记以使标签不再包含复选框将意味着不会调用侦听器。

答案 2 :(得分:1)

事件泡沫。

复选框是标签的子节点。单击复选框。事件泡沫到标签。然后警报弹出两次。

单击复选框以防止警报弹出两次。您可以将onck功能更改为:

wow.onclick = function(e){
    alert('hi');
    stopBubble(e);
}


function stopBubble(e)  
{  
    if (e && e.stopPropagation)  
        e.stopPropagation()  
    else 
        window.event.cancelBubble=true 
}  

希望这对你有用。

答案 3 :(得分:0)

Label标签将与其中的输入标签相关联。因此,当您单击标签时,它还会触发输入的单击事件,然后冒泡到标签本身。

见:

document.getElementById("winput").addEventListener('click', function(event){
     alert('input click');

     //stop bubble
     event.stopPropagation();

 }, false); 

http://jsfiddle.net/96vPP/

答案 4 :(得分:0)

再次将头撞到这个陷阱,并决定向自己证明它所做的事情,希望能帮助我记住。为了帮助可能对上述内容不够清楚的将来的人们,这里我举一个例子。

https://jsfiddle.net/ashes/0bcauenm/

$(".someBigContainer").on("click", "input[type=checkbox]", ()=> {
    $output.val("Clicked: checkbox\n" + $output.val());
}); 

edit:添加带有代码片段的链接。

答案 5 :(得分:0)

这可能是最简单的答案。只需在文本周围添加一个跨度并停止事件传播。

window.onload = function(){
    var wow = document.getElementById("wow");
    wow.onclick = function(){
        alert("hi");
    }
}
<label id="wow">
    <input type="checkbox" name="checkbox" value="value">
    <span onclick="event.stopPropagation()">Text</span>
</label>

或者没有内联javaScript

window.onload = function(){
    var wow = document.getElementById("wow");
    wow.onclick = function(){
        alert("hi");
    }

    var span = document.getElementsByTagName("span")[0];
    span.onclick = function(event){
        event.stopPropagation();
    }
}
<label id="wow">
    <input type="checkbox" name="checkbox" value="value">
    <span>Text</span>
</label>

答案 6 :(得分:0)

对于那些使用 React 和 Material UI 的人 - 我在我的一个表单上遇到过这个问题。 event.preventDefault() 正在阻止事件冒泡,如已接受的答案所述。

  <Button
    onClick={(event) => {
      event.preventDefault()
      this.handleCardClick(planName)
    }}
  >
    <FormControl component="fieldset">
      <RadioGroup
        row
        value={selectedPlan}
      >
        <FormControlLabel
          control={<Radio color="secondary" />}
          label={label}
        />
      </RadioGroup>
    </FormControl>
  </Button>