今天同事遇到这个很奇怪的问题,深入探查了一下,才发现其中奥妙。
最初怀疑是重复绑定造成的,但精简代码到最小,仍然出现。在排查了jQuery版本,css覆盖层,各种能想到的可能性后,仍一筹莫展。
静下心来慢慢梳理,通过输出事件来源,才猛然发现,原来绑定不同的元素,其事件来源是不同的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
HTML <label id="label"> <input id="input" type="radio" /> label </label> JavaScript jQuery("#label").click(function(e){ console.log(e.target.id) }) (单击input)输出 input (单击label)输出 label input JavaScript jQuery("#input").click(function(e){ console.log(e.target.id) }) (单击input或label)输出 input |
找到了事件来源,似乎看到了蛛丝马迹,赶紧顺藤摸瓜。推测如下:
1.绑定在label。单击input后,触发input本身的click事件。单击label后,首先触发label本身的click事件,然后由于“某种原因”触发了input的click事件,进而事件冒泡至label,再次触发label的click事件。
2.绑定在input。单击input后,触发input本身的click事件。单击label后,由于“某种原因”触发了input的click事件。
将该示例在IE8-11、chrome中测试,表现相同。突然想起来,label是有一个for属性,标准的用法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
HTML <label id="label" for="input">label</label> <input id="input" type="radio" /> JavaScript jQuery("#label").click(function(e){ console.log(e.target.id) }) (单击input)无输出 (单击label)输出 label JavaScript jQuery("#input").click(function(e){ console.log(e.target.id) }) (单击input或label)输出 input |
标准用法中,单击label,仍会触发input的click事件。
对以上两个示例进一步测试,替换input:radio为其他类型(如input:checkbox或input:text),表现相同。
由此可以得出结论,上述“某种原因”,是浏览器的特性。当单击与input相关(嵌套或for属性指定)的label时,自动触发input的click事件。
原来是个之前从未留意过的“坑”,如果不是今天遇到,还不知要潜伏多久。