页面一打开就默认选中单选框,唯一可靠方式是在HTML中直接添加checked属性;浏览器只认该属性是否存在,与值无关,且同name组内仅首个checked生效。

直接加 checked 属性是唯一可靠方式
页面一打开就默认选中某个单选框,必须在 HTML 标签里写 checked,而不是靠 JS 补、CSS 画、或者改 value。浏览器只认这个属性是否存在——写了就选中,不写就不选中,不管后面有没有 checked="false" 或 checked="0",这些都无效。
常见错误现象:
-
<input type="radio" name="mode" value="dev" checked>:依然被选中(浏览器忽略值,只看属性存在) - 服务端模板渲染时,多个同名 radio 都加了
checked:浏览器只采纳第一个,但逻辑上已混乱 - 用
setAttribute('checked', '')动态添加:能显示视觉选中,但表单提交时可能不包含该值(尤其在未触发重绘或 hydration 失败时)
name 相同才是一组,且只能有一个 checked
单选框的互斥行为完全依赖 name 属性。如果两个 radio 的 name 值大小写不同(比如 "Theme" 和 "theme"),它们就不是一组,checked 各自生效,但用户点击也无法取消对方。
使用场景中容易踩的坑:
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
- 前后端字段命名不一致(如后端传
user_role,前端写成userRole),导致分组失效 - Vue/React 中用
v-model或value绑定,但忘了确保初始 state 值与某一个value完全匹配(字符串相等,不是 loosely equal) - SSR 渲染时服务端写了
checked,客户端初始 state 却是空值,hydration 失败,浏览器强制接管并清空选中状态
JS 动态设置要用 .checked = true,不是 setAttribute
运行时想切换选中项,必须操作 DOM 元素的 checked 属性,而不是 HTML 属性。前者影响实际状态和表单提交,后者只影响初始渲染或静态标记。
实操建议:
- 用
document.querySelector('input[value="pro"]').checked = true,不要用setAttribute('checked', '') - 设完
.checked = true后,如果业务逻辑监听了change事件,得手动触发:element.dispatchEvent(new Event('change', { bubbles: true })) - 更稳妥的做法是调用
element.click():它既更新状态,又触发原生事件链,兼容性更好 - 注意时机:元素必须已挂载到 DOM,否则
click()无效;可用requestAnimationFrame或DOMContentLoaded包裹
别忽略 label 关联和可访问性
单独放一个 <input type="radio"> 不仅难点击,还对屏幕阅读器不友好。必须配 label,且推荐用嵌套方式而非 for/id,减少 id 冲突风险。
正确写法示例:
<label> <input type="radio" name="format" value="json" checked> JSON </label> <label> <input type="radio" name="format" value="xml"> XML </label>
容易被忽略的点:
- 没加
label时,移动端点击热区极小,用户反复点不中 - 用了
for/id但 id 重复或拼错,label点击完全失效 - CSS 隐藏了原生 radio(
position: absolute; clip: rect(0,0,0,0))却没同步处理 focus outline,键盘导航中断
name 分组错位、SSR 与客户端初始值不一致、以及 JS 设置后忘了派发事件——这三处一漏,表单逻辑就断在看不见的地方。


















