为什么复选框会失控?一个 Bug 的故事
\n\n想象一下:你在编写一个网站注册表单。有一个“同意条款”的复选框。用户点击——勾选标记出现。一切正常。然后你决定用 jQuery 添加一个“全选”按钮。你写下 $('#agree').attr('checked', true)——然后……什么也没发生。或者勾选标记只出现一次,然后就无法取消了。熟悉吗?
这个问题是 Stack Overflow 上最热门的问题之一。成千上万的开发者都在同一个坑里栽跟头。今天我们就来弄清楚为什么会这样,以及如何正确使用 jQuery 设置复选框的 checked 状态。
\n\n简而言之:问题出在哪里?
\n\n问题在于,许多新手(甚至不完全是新手)使用 .attr() 方法来管理 checked 属性。但从 jQuery 1.6 开始,正确的方法是使用 .prop()。属性(attribute)和特性(property)之间的区别是关键主题,我们现在就来详细讲解。
属性 vs 特性:有什么区别?
\n\n我们简单解释一下。HTML 属性是你在标记中写的内容:
\n\n<input type="checkbox" id="agree" checked>\n\n这里的 checked 属性设置了复选框的初始状态。但当用户点击时,改变的是 DOM 元素的 特性(property),而属性保持不变。
.attr() 方法操作的是属性,而 .prop() 操作的是特性。由于我们关心的是复选框的当前状态(它是动态变化的),所以我们需要使用 .prop()。
代码中如何体现
\n\n下面是一个简单的例子,展示了区别:
\n\n<!-- HTML -->\n<input type="checkbox" id="myCheckbox">\n<button id="setChecked">设置勾选</button>\n<button id="removeChecked">取消勾选</button>\n\n<script>\n// 正确的方法 (jQuery 1.6+)\n$('#setChecked').click(function() {\n $('#myCheckbox').prop('checked', true);\n});\n\n$('#removeChecked').click(function() {\n $('#myCheckbox').prop('checked', false);\n});\n</script>\n\n注意:我们传递的第二个参数是 true 或 false——布尔值。这一点很重要。
新手常见错误(以及如何避免)
\n\n错误 1:使用 .attr() 设置 checked
\n\n// ❌ 错误\n$('#myCheckbox').attr('checked', true);\n\n// ❌ 也是错误的\n$('#myCheckbox').attr('checked', 'checked');\n\n为什么这样不好?因为 .attr() 设置的是属性,而不是特性。在用户第一次点击后,属性可能保持不变,而特性已经改变。结果就是行为不一致。
错误 2:传递字符串而不是布尔值
\n\n// ❌ 错误\n$('#myCheckbox').prop('checked', 'true'); // 字符串,不是布尔值\n\njQuery 会把字符串转换成布尔值吗?在某些情况下——是的。但依赖这一点是不好的实践。始终传递不带引号的 true 或 false。
错误 3:读取状态时忘记使用 .prop()
\n\n// ❌ 错误\nif ($('#myCheckbox').attr('checked')) { ... }\n\n// ✅ 正确\nif ($('#myCheckbox').prop('checked')) { ... }\n\n读取当前状态——只能使用 .prop()。
完整示例:带复选框和控制按钮的表单
\n\n让我们把所有内容整合起来。假设我们有一个选项列表,用户可以选择,还有“全选”和“取消全选”按钮。
\n\n<!DOCTYPE html>\n<html>\n<head>\n <title>使用 jQuery 管理复选框</title>\n <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script>\n</head>\n<body>\n <h3