HTML 表单中单选按钮想要实现互斥选择,关键在于 name 属性值必须完全一致;未被选中的 radio 不会出现在表单提交数据里;使用 JS 获取当前选中项时,推荐通过 querySelector('input[name="xxx"]:checked') 直接拿到选中值。

单选按钮 name 属性必须一致才能互斥
在 HTML 里, 能否组成一组单选按钮,决定因素不是 class,也不是页面中的排列位置,而是所有选项的 name 属性值是否完全相同。浏览器只根据这一点来判断:同名的 radio 会自动互斥,提交表单时也只会传递当前选中的那个 value 值。
实际开发中最常见的问题,就是复制代码时忘记统一修改 name,结果表面上看像单选,实际上每个选项都能单独勾选;另外如果大小写不一致,比如 gender 和 Gender,在部分旧环境下同样可能导致单选失效。
- ✅ 正确:
、 - ❌ 错误:
和
表单提交时,未选中的 radio 不会出现在 FormData 中
无论是原生表单提交(method="POST" + action),还是通过 FormData 收集表单数据,**没有被选中的 都不会被提交进去**。这不是异常,而是 HTML 表单提交机制的标准行为。后端收到的结果只有两种情况:要么字段存在并带有值(例如 level=advanced),要么这个字段根本不存在。
这也说明,不能简单地把“没收到值”理解为某个默认选项,而应该由后端明确判断该字段是否存在;如果前端希望页面加载时就默认选中某个单选项,就必须设置 checked 属性,而且同一组里只能有一个默认选中。
- 设置默认项:
- JS 动态检查是否选中:
document.querySelector('input[name="theme"]:checked'),返回null表示没选 - 用
FormData获取时:new FormData(form).get('theme'),未选则返回空字符串(不是null)
Ja vaScript 获取值时别直接 querySelectorAll
如果想用 JS 获取当前选中的 radio 值,最省事也更推荐的写法,并不是先用 querySelectorAll 找到全部 radio 再逐个遍历,而是直接使用带 :checked 伪类的选择器一次性定位:document.querySelector('input[name="mode"]:checked')。这样可以直接返回当前唯一被选中的元素,或者在未选择时返回 null,相比遍历方式更直观,也更高效。
需要注意的是,如果页面中存在多个同名的 radio 组,例如两个不同表单都使用了 name="size",那么这个选择器可能会跨表单匹配。因此最好保证当前作用范围内 name 唯一,或者在指定父容器、指定 form 中进行查找:
- 全局取值:
document.querySelector('input[name="size"]:checked')?.value - 限定表单内:
form.querySelector('input[name="size"]:checked')?.value - 避免报错:一定要用可选链
?.value,否则未选中时访问null.value会抛TypeError
后端接收不到值?先确认表单 method 和 enctype
如果表单提交后服务端无法收到 radio 的值,通常问题并不在 JS 获取单选按钮值这一步,而更可能是表单本身的配置不正确。尤其要重点检查以下两项:
会把提交值直接拼接到 URL 后面,可以通过浏览器地址栏快速确认是否出现了类似?level=advanced的参数enctype="multipart/form-data"主要用于文件上传,但即便设置了它,**普通表单字段(包括 radio 单选按钮)依然可以正常提交**,不需要额外手动处理 —— 很多人误以为必须自己 append,其实并没有这个必要- 若用
fetch提交,别忘了body: new FormData(form),且服务端解析逻辑要匹配(如 Express 需urlencoded()或multer)
还有一个经常被忽视的细节是:如果 radio 的 value 中包含空格或特殊字符,例如 value="full time",虽然写法合法,但部分后端框架可能会默认执行 trim、转义或其他处理。为了减少歧义、提升表单提交兼容性,通常建议使用短横线或下划线这样的命名方式,例如 full-time。
