Label 和 checkbox 不为人知的小秘密
最近开发的时候同事遇见了一个问题,点击label的时候改变checkbox的属性,或许大家觉得这是一个很简单的问题,然而这里面却蕴藏着一个大坑!
举例说明:
页面简单,就是一个
<input id="input" type="checkbox">
和一个
<label id="label" for="t">点我</label>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> </head> <body> <div> <input id="input" type="checkbox"> <label id="label" for="input">点我</label> </div> </body>
操作的思路大致是点击给label添加一个事件,通过判断checkbox当前的状况来改变checkbox的状态,代码如下:
<script> var inputELe = document.getElementById('input'); //input元素 var labelEle = document.getElementById('label'); //label元素 labelEle.addEventListener('click',function(e){ //给label添加事件
alert('我被点了'); if(inputELe.checked){ //如果当前是选中状态 inputELe.checked = false //置为false }else{ inputELe.checked = true //否则置为true } }); </script>
乍一看代码很完美,完全能够满足要求,但是实际上呢?看gif图:
可以看到,无论我怎么点击,checkbox都没有变成选中状态。这是一个很奇怪的现象。要解释这个现象要知道label和这个input之间的通信问题。
点击label触发checkbox状态改变和直接点击checkbox触发改变的过程是不一样的,
直接点击checkbox会立即改变checkbox的状态,如下:
假如现在代码如下:
inputELe.addEventListener('click',function(e){ //只给input元素添加事件 alert(inputELe.checked); });
可以看到,当input的状态在视图上还没改变的时候,他的checked的值已经发生了改变了,而如果在label上加事件呢?
labelEle.addEventListener('click',function(e){ alert(inputELe.checked); });
这样则在点击label的时候,并没有立刻改变checkedbox的状态,而是当注册在label上的事件alert完了之后,才改变的checkbox的状态。造成这种现象的原因在于:
点击label的时候,label有限处理自己对应的事件,然后再通知checkbox改变状态,而且,只会通知checkbox改变状态,并不告诉他要改变成true还是false,checkbox当前是true就变成false,是false就改成true.
这样便可以理解一开始的程序为什么没有改变成功状态了。
再把代码拷过来,一步一步看,假设一开始checkbox没有选中:
labelEle.addEventListener('click',function(e){ //给label添加事件
alert('我被点了');
if(inputELe.checked){ //由于点击label的时候,还没有告诉checkbo改变状态,所以当前值是false,执行else语句
inputELe.checked = false //置为false
}else{
inputELe.checked = true //所以这个时候checkbox应该变成了true,状态改变成功!
}
});
上面的方法确实改变了checkbox的状态但是,执行完这个方法后,label还有事要做,那就是通知checkbox改变状态,由于这时候执行的方法里面已经把checkbox的状态改成了true,所以当checkbox接到label的消息的时候,又会把自己变成false,
所以改变状态并没有成功,一来一回又被变成了原样了。checkbox一开始为false的时候也一样。
所以当大家使用label和checkbox(radio也一样)组合的时候,一定注意:不要把事件加给label,却在点击时间里去改变checkbox的状态!正确的做法是始终给checkbox添加事件并且改变checkbox的状态。
最后,告诉大家这个组合的使用场景:
就是组合成一个这样的开关,通过隐藏input并给label添加样式:after 和 :before 伪元素即可,当然注意操作的时候不要陷入上面的坑里面。