问题描述
在项目中遇到一个bug——label标签上绑定了一个返回一层的点击事件,然鹅每次点击都会返回两层!!
经调试发现,label标签中包裹input,而事件绑定在label标签中时,点击label区域,事件会执行两次。
问题测试
<label onclick="labelConsole()">
<input type="checkbox" onclick="inputConsole()">勾选协议
</label>
function labelConsole (){
console.log('label_click 这是我们想要的操作')
}
function inputConsole (){
console.log('input_click')
}
-
点击label区域(不直接点击input区域):label上的事件被触发执行一次,同时子元素input本身也绑定有click事件,触发后又冒泡传递给label,又触发了一次label绑定事件。
-
直接点击input区域:触发input绑定事件后又冒泡传递给label,触发了label的绑定事件。
分析原因
- 元素默认绑定click事件
一些元素如<a>、<button>、<input>本生就默认绑定了click事件,即使你不绑定,click事件发生时他们也会接收到。 - label标签的扩展性
它把所包含的input的用户交互区域扩展了,注意的是label和所包含的input都开始绑定默认事件,此时会发生事件冒泡现象。在label上的click事件的处理函数会触发2次就是由于:第一次是label自己接收到事件,执行处理函数,第二次是input接受到事件后冒泡传递给label,再次触发处理函数。
解决方案
方案1:将原绑定于label的事件,直接绑定于input上。
<label>
<input type="checkbox" onclick="labelConsole()">勾选协议
</label>
此时,当点击label区域或者直接点击input区域,由于checkbox本身有默认click监听器,所以会触发一次我们绑定的事件。
方案2:阻止事件冒泡
<label onclick="labelConsole()">
<input type="checkbox" onclick="inputConsole()">勾选协议
</label>
function labelConsole (){
console.log('label_click 这是我们想要的操作')
}
function inputConsole (){
console.log('input_click');
window.event? window.event.cancelBubble = true : e.stopPropagation();
}
点击label非input区域的时候效果如上,这种方法看似实现了我们的需求,只让我们想要的操作触发一次,但是如果你直接点击的是input,那就跪了。没错,当你直接点击input的时候只会触发input的绑定事件,而我们绑定在label上的事件则无人问津。这并不符合预期,所以方案2不太可取。
网友评论