首页 > 技术文章 > 复选框的一些事儿

jhmydear 2015-08-27 15:21 原文

原文地址:复选框的一些事儿

对复选框总觉得云里雾里,判断选中与未选中的方法总觉得不明白,调整复选框与文字的对齐怎么调都没用,以前总没有动力去花一个真正的时间去解决这些问题,受到今天项目的启发,所以来弄清楚一下。

1、先来说说选中与未选中的方法与判断问题

在表单中,

 1 <form action="">
 2 
 3 <input type="checkbox" id="test">复选框
 4 
 5 </form>
 6 
 7 <script>
 8 $(function(){
 9 
10 var test = $('#test').val();
11 console.log(test); //on
12 
13 });
14 </script>

 

不管你选没选中,复选框的val都是on,所以肯定是不能用这个来判断的。

在原生的js中,我们可以用对象的checked属性,如下:

var test = document.getElementById('test').checked;
console.log(test); //false

比如我们用来点击事件发生时判断:

 1 <form action="">
 2 
 3 <input type="checkbox" id="test" onclick="check(this)">复选框
 4 
 5 </form>
 6 
 7 <script>
 8 
 9 function check(obj){
10 console.log(obj.checked);
11 }
12 </script>

 

你会发现你可以自由的判断是否选中了

7`S8L0M[KOSY86WSNR21QHN

 

但很多情况下我们都是结合jquery来使用的,在jquery中,很多人都是使用的$().addAttr('checked', 'checked');  给这个复选框的DOM添加checked属性,其实这个并没有真正的选中复选框,来看个例子:

 1 <form action="">
 2 
 3 <input type="checkbox" id="test2" checked onclick="check(this)">复选框2
 4 
 5 </form>
 6 
 7 <script>
 8 function check(obj){
 9 console.log(obj.checked);
10 }
11 </script>

 

此时你会发现

11

 

这里是我们添加的checked属性,添加了这个属性,默认是选中的,也就是说,添加了checked属性后js对象的checked属性默认是选中的,我们打印下:

var test = document.getElementById('test2').checked;
console.log(test);  //true

但是我们点击复选框去掉选中的时候,DOM结构中的checked属性是不会被去掉的,但此时js对象的checked实际上是等于false的。也就是说这并不是一个可逆的过程,需要我们手动移除attr为checked的属性。

但比如下种情况的时候

1 <ul>
2 <li style="background:#eee;">
3 <input type="checkbox" id="test3"> 复选框3
4 </li>
5 </ul>

我想要实现的是点击li元素的文字就可以实现选中状态,当然点击复选框本身也可以实现选中状态,那么应该怎么做呢?

当然首先想到的肯定是:

 1 <ul>
 2 <li style="background:#eee;" onclick="check3()">
 3 <input type="checkbox" id="test3"> 复选框3
 4 </li>
 5 </ul>
 6 
 7 <script>
 8 $(function(){
 9 
10 var test3 = document.getElementById('test3');
11 function check3(){
12 if(test3.checked)
13 test3.checked = false;
14 else
15 test3.checked = true;
16 }
17 
18 </script>

 

此时,你会发现点击li元素的确可以实现选中,但是,点击复选框本身就没有任何反应了,这是为什么?为什么?为什么呢?

想想就知道是事件冒泡的问题了,复选框本身在li元素中,li元素本身也会有点击事件,当你点击复选框时,它其实是执行了的,但后来又执行了一次li元素的点击事件,导致复选框看起来没变化。

在这里我们可以阻止默认事件的发生,打印结果:

var test3 = document.getElementById('test3');
function check3(){
if(test3.checked)
test3.checked = false;
else
test3.checked = true;
}

$('#test3').click(function(event){
console.log(this.checked);
event.stopPropagation();
});

在这里就要说说阻止默认事件和行为的3种方法的区别:(此处粘贴)

1.event.stopPropagation();
事件处理过程中,阻止了事件冒泡,但不会阻击默认行为(它就执行了超链接的跳转)
2.return false;
事件处理过程中,阻止了事件冒泡,也阻止了默认行为(比如刚才它就没有执行超链接的跳转)

3.event.preventDefault();
如果把它放在头部A标签的click事件中,点击“点击我”。
会发现它依次弹出:我是最里层---->我是中间层---->我是最外层,但最后却没有跳转到百度
它的作用是:事件处理过程中,不阻击事件冒泡,但阻击默认行为(它只执行所有弹框,却没有执行超链接跳转)

这里就要来说说jquery的prop()和attr()的区别,其实前面也提到过,this.checked  和  $(this).attr('checked')的区别,this指的是js对象,而$(this)指的是DOM对象,他们拥有的属性都是不一样的,比如

<a id="a" href="ymblog.net"></a>

$(this).attr()属性就包含了id和href,而不包含style.width或者style.color,因为这些在js对象的style属性里面,

$('#a').click(function(){
console.log(this.id);  //a
console.log(this.href);  //ymblog.net

console.log($(this).style);  //undefined
});

说明this对象中包含了DOM对象的属性,反之则不是。

在这里的prop和attr也是一样的,区别就好比this.checked与$(this).attr('checked');一样。

详细可以参考这篇文章:jQuery中attr和prop方法的区别

了解完这2个属性以后,让我们再来回顾前面的li元素中包裹的复选框的情况,在这里这样使用呢?

如下:

 1 <ul>
 2 <li style="background:#eee;" id="test4">
 3 <input type="checkbox" > 复选框4
 4 </li>
 5 </ul>
 6 <a href="#" id="aaa">移除</a>
 7 
 8 <script>
 9 
10 $('#test4').click(function(){
11 $(this).find('input').attr('checked', 'checked');
12 })
13 $('#aaa').click(function(){
14 $('#test4').find('input').removeAttr('checked');
15 });
16 </script>

 

如果你去运行,试过之后就会发现,第一次点击li元素,它会勾选,然后点击移除它会去掉勾选,这似乎很正常啊,但当你第二次点击以后,它不勾选了,没反应了了,为什么呢?

我们可以来打印第一次点击以后的this.checked

$('#test4').click(function(){
$(this).find('input').attr('checked', 'checked');
console.log(document.getElementById('test5').checked);
})
$('#aaa').click(function(){
$('#test4').find('input').removeAttr('checked');
console.log(document.getElementById('test5').checked);
});

  

我们每次都打印一下,下面是运行结果:

222

 

你会看到第一次点击以后,为input添加checked属性,this.checked = true;点击移除checked属性以后,this.checked = false;但是当第二次点击为input添加checked属性时,input却没有被勾选,也就是没有被checked。这是为什么?谁能告诉我?为什么?(待解决~)

在这里如果再用prop()checked一次,又会正常了,这也证明了前面的正确性

$('#test4').click(function(){
$(this).find('input').attr('checked', 'checked');
$(this).find('input').prop('checked', true);
})
$('#aaa').click(function(){
$('#test4').find('input').removeAttr('checked');
$('#test4').find('input').prop('checked', false);
});

  

在这里觉得移除prop('checked',false);可以去掉,为什么呢?

$('#test4').click(function(){
$(this).find('input').attr('checked', 'checked');
$(this).find('input').prop('checked', true);
console.log(document.getElementById('test5').checked);
})
$('#aaa').click(function(){
$('#test4').find('input').removeAttr('checked');
// $('#test4').find('input').prop('checked', false);
console.log(document.getElementById('test5').checked);
});

  

你会发现,不起作用的只有第二次点击选中的时候attr('checked', 'checked');而removeAttr('checked');每次都起到了checked = false;的作用。

在这里我似乎不能完全理解明白,有弄清楚的大神麻烦私信一份给我谢谢(472102644@qq.com)!

但我们在这里的解决办法还是有的,

比如上面的input复选框被包裹在一层li元素的情况下,你在为input添加checked属性以后,再为它的this对象的checked属性赋值为true,这样就确保了input真正的选中。

出现问题的根本原因在于,你为input复选框(第一次是有效果的)添加checked属性以后,它并不会被checked,也就是说$(this).find('input')[0].checked == false;始终等于false。

也就是这段代码,感兴趣的可以去试试

 1 <ul>
 2         <li style="background:#eee;" id="test6">
 3             <input type="checkbox" id="input"> 复选框5
 4         </li>
 5     </ul>
 6 
 7     <script>
 8     $('#test6').click(function(){
 9         if( $(this).find('input').attr('checked') == 'checked'){
10             $(this).find('input').removeAttr('checked');
11             console.log($(this).find('input')[0].checked)
12         }
13         else{
14             $(this).find('input').attr('checked',"checked");
15             console.log($(this).find('input')[0].checked)
16         }
17 
18     </script>

 有人说,那你用prop判断不久可以了,你用prop后,点击input事件就会冒泡了,又回到了前面说的问题。

关于样式的深入理解下一篇再学习研究,这里就先到这儿了。

参考文章:

jQuery中attr和prop方法的区别

checkbox复选框的一些深入研究与理解

jquery 事件冒泡的介绍以及如何阻止事件冒泡

推荐阅读