【问题标题】:Why click event is fired twice?为什么点击事件被触发两次?
【发布时间】:2014-11-20 20:09:43
【问题描述】:

谁能告诉我,为什么以下代码会触发两次事件: http://jsfiddle.net/m8heyzgz/3/ 请打开您的控制台,firefox 或 chrome 有控制台,然后观察结果 你点击'div1',然后 事件演练顺序将是:

  • div3
  • div2
  • div1
  • div3
  • div2
  • div1

据我所知,捕获阶段可以是从上到下,冒泡阶段可以是从目标到父节点。

我的问题是为什么,它以相同的顺序被触发了 2 次?

HTML:

<div id="div1">
    <div id="div2">
        <div id="div3">
            <form>
                <ul>
                    <li>
                        <label>                            
                            <div>
                                <div>div1</div>                            
                            </div>
                            <div>
                                <div>div2</div>                            
                            </div>
                            <div>                                  
                                <input type="checkbox" name="div3" value="div3" />
                            </div>
                        </label>
                    </li>
                </ul>
            </form>
        </div>
    </div>
</div>

js:

var d1 = document.getElementById('div1');
var d2 = document.getElementById('div2');
var d3 = document.getElementById('div3');

var f = function(e) {
    console.log(e.currentTarget);
}

d1.addEventListener('click', f);
d2.addEventListener('click', f);
d3.addEventListener('click', f);

【问题讨论】:

  • 在 Opera 中也可以重现。
  • 这应该会有所帮助:stackoverflow.com/questions/19595084/…
  • @juvian,如果您在第一个复选框下添加另一个复选框,您将选中第一个复选框。但是,如果新复选框(如果添加新复选框)也在同一个父级下,为什么在这种情况下只检查第一个复选框?
  • 为什么只有第一个?因为只有一个在语法上是有效的。 label 只能绑定到一个元素。通过将元素包裹在label 中,或者将labelfor 属性设置为元素的id

标签: javascript html events addeventlistener


【解决方案1】:

我。为什么顺序一样?

这两个波的顺序是相同的,因为您只看到两个事件的冒泡阶段,而不是捕获阶段。如果你想看到捕获,你的addEventListener's third parameter (useCapture) 应该是真的。

二。为什么要开2次?

  1. 当您点击标签的内容时,标签会触发第一个点击事件。
  2. 第二次点击事件是通过合成点击从标签的复选框触发的。

+1。什么是合成点击?

由程序代码而非输入设备发起的点击。 (它fires a click event。)

+2。为什么会发生合成点击?

因为是the run synthetic click activation steps algorithm的第四步。

+3。为什么浏览器会运行这个算法?

因为它尊重the W3C's recommendation

“标签元素的(...)激活行为(...)应该匹配平台的标签行为。” “例如,在单击复选框标签选中复选框的平台上,单击标签 (...) 可能会触发用户代理在输入元素上运行合成单击激活步骤,就好像元素本身已由用户触发一样(...)"

【讨论】:

【解决方案2】:

查看 HTML5 规范:

"除非以下规则另有规定,否则标签元素没有标签控件...

...如果未指定 for 属性,但 label 元素有一个可标注元素后代,那么按树顺序排列的第一个此类后代就是 label 元素的带标签控件。...

...例如,在单击复选框标签选中复选框的平台上,单击以下 sn-p 中的标签可能会触发用户代理在输入元素上运行合成单击激活步骤,就好像元素本身已经被用户触发了一样……”

http://www.w3.org/TR/html5/forms.html#labeled-control

因此,点击您的标签元素会在标签中的第一个输入上触发一个合成点击事件 - 回答您 cmets 中的问题。

【讨论】:

  • 如果你想说服自己,我已经对你的小提琴进行了着色,以明确哪些元素在你的控制台中触发了什么jsfiddle.net/m8heyzgz/7
  • 很高兴我们能为您提供帮助。请您接受其中一个问题好吗?对于未来的访问者来说,立即看到答案很有用。我试图尽可能清楚地回答您问题的两个部分,没有可能分散注意力的部分。如果你不能决定,那么just flip a coin。 ;)
  • @dany 我很高兴 Tamas 最初的回答更全面,他为将其更新为面向未来访客的广泛而清晰的答案所付出的努力值得被接受为答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多