【问题标题】:Why the onclick element will trigger twice for label element为什么 onclick 元素会为 label 元素触发两次
【发布时间】:2014-07-01 02:05:41
【问题描述】:

      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>

这是我的代码,当我点击“文本”时,它会提示 hi 两次,但当我点击框时,onclick 元素只会触发一次,为什么?

【问题讨论】:

  • 你需要windows onload的警报吗?
  • @Niang nope 当文本被点击时

标签: javascript html


【解决方案1】:

当您点击标签时,它会触发点击处理程序,并且您会收到警报。

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

如果您将 HTML 更改为此,您将不会收到双重警报:

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

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

DEMO

【讨论】:

  • 我想我从来没有注意到这一点,因为我通常只是将“点击”处理程序放在&lt;input&gt;,而不是标签上。这是一种奇怪的行为,我不确定我能想出它有用的原因。
  • 您也可以停止事件传播。
  • 理想情况下应该绑定一个更改事件处理程序。非常适合可访问性。
  • @FelixKling 您无法将更改处理程序绑定到标签 AFAIK。
  • @MMiller 是的,但您必须在复选框上添加一个点击处理程序。
【解决方案2】:

如果您的意图是只响应标签上的点击而不是复选框上的点击,您可以查看 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);
}

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

【讨论】:

    【解决方案3】:

    事件气泡。

    复选框是标签的子节点。您单击复选框。标签的事件气泡。然后alert弹出两次。

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

    wow.onclick = function(e){
        alert('hi');
        stopBubble(e);
    }
    
    
    function stopBubble(e)  
    {  
        if (e && e.stopPropagation)  
            e.stopPropagation()  
        else 
            window.event.cancelBubble=true 
    }  
    

    希望这对你有用。

    【讨论】:

    • 我认为这不是正确的答案。包含&lt;label&gt; 标记的事件处理程序应该只接收一次冒泡事件。浏览器生成两个“点击”事件,一个以&lt;input&gt;元素为目标,一个以&lt;label&gt;为目标。
    • 两次弹出。一个来自点击标签。另一种是单击标签的输入气泡。我认为这可以解释这一点。:)
    • 不,冒泡只涉及 一个 事件对象,该对象传递给父元素上的事件处理程序。在这种情况下,事件对象在两次调用处理程序时是不同的。
    • 它不起作用:jsfiddle.net/barmar/fMMAz/5 从标签到复选框的传播不会冒泡,这是标签特有的东西。
    • 不,它没有。我点击了“文本”并在 Chrome 中收到了两个警报。
    【解决方案4】:

    标签标签将与其中的输入标签相关联。所以当你点击标签的时候,也会触发输入的点击事件,然后冒泡到标签本身。

    看这个:

    document.getElementById("winput").addEventListener('click', function(event){
         alert('input click');
    
         //stop bubble
         event.stopPropagation();
    
     }, false); 
    

    http://jsfiddle.net/96vPP/

    【讨论】:

      【解决方案5】:

      再次一头扎进这个陷阱,并决定证明它对自己做了什么,希望能帮助我记住。为了帮助将来可能对上述内容还不够清楚的人,这里是我制作的示例。

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

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

      编辑:添加了带有代码片段的链接。

      【讨论】:

        【解决方案6】:

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

        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>

        或者没有 inline-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>

        【讨论】:

        • 这些解决方案都不能 100% 正常工作。您有多个空格字符落入 找到:在复选框之前,在复选框和“文本”之间的“文本”之前,如果您点击正确,您会收到双重警报。此外,如果您非常准确地单击复选框边框外 1px 的任意位置,则会收到双重警报。 (我使用的是 Windows 10,Chrome 98)
        【解决方案7】:

        对于那些使用 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>
        

        【讨论】:

          【解决方案8】:

          使用change 代替click 来监听事件

          【讨论】:

            猜你喜欢
            • 2014-10-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-03-15
            • 1970-01-01
            • 2021-03-06
            相关资源
            最近更新 更多