应使用 onchange 事件监听 radio 选中状态变化,而非 onfocus;因 radio 默认不可聚焦,焦点通常落在 label 上,change 在选项状态真正改变时触发且只执行一次。

radio元素本身不触发onfocus事件
HTML规范里,<input type="radio"> 默认不能获得键盘焦点(除非显式设置 tabindex),所以直接写 onfocus 属性或用 addEventListener('focus', ...) 绑定,基本不会执行——用户点击它时焦点实际落在了 label 上(如果用了关联的 <label for="id"></label>),或者根本没触发 focus 流程。
想监听“被选中”应该用 onchange 而不是 focus
绝大多数场景下,你真正关心的是“用户选择了这个选项”,而不是“它获得了焦点”。这时必须用 change 事件:
<input type="radio" name="gender" value="male" id="male">
<label for="male">男</label>
<script>
document.getElementById('male').addEventListener('change', function() {
if (this.checked) {
console.log('男被选中');
}
});
</script>
-
change在用户点击后、选项状态真正改变时触发(且只触发一次) - 不要用
click:它会在每次点击都触发,包括重复点已选中的项 - 务必检查
this.checked,因为change也会在取消选中时触发(比如切换到同组其他 radio)
真要监听焦点?得手动加 tabindex 并处理可访问性
极少数情况(如辅助技术适配、自定义焦点样式),你需要让 radio 可聚焦。这时必须:
- 给
<input>显式添加tabindex="0" - 用
focus事件监听,但注意:键盘 Tab 进入时才触发,鼠标点击默认不触发 - 同时补充
blur和keydown(比如空格键选中)逻辑,否则会破坏可访问性 - 视觉上需用
:focus-visible或 JS 切换 class 来显示焦点框,否则用户看不见当前焦点在哪
示例片段:
立即学习“前端免费学习笔记(深入)”;
生成可在 deepbi 沙箱 iframe 内运行或作为独立文件运行的交互式 HTML 页面,使用 `window.deepbi` JS SDK 实现数据查询、空间管理、文件浏览及用户操作。当用户提出以下需求时启用该能力: - 创建 KPI 仪表盘、数据表格、文件浏览器、成员列表、管理页面; - 明确要求“转成 dhtml”、“转译成 HTML”、“把 XX 页面转成……”、“控制台页面”、“管理后台”、“DeepBI 页面迁移”; - 提及位于 `apps/console/src/featur
<input type="radio" name="theme" value="dark" id="dark" tabindex="0">
<label for="dark">深色主题</label>
<script>
document.getElementById('dark').addEventListener('focus', () => {
console.log('dark radio 获得键盘焦点');
});
</script>
更稳妥的做法:把事件绑在 label 上
如果只是想响应“用户点了一下这个选项区域”,最简单可靠的方式是监听关联的 <label></label>:
- label 点击天然会触发对应 radio 的
change - label 本身可聚焦、有默认 focus 样式,无需额外配置
- 用户无论点文字还是点 radio 圆圈,都能捕获到
代码只需一行:
document.querySelector('label[for="male"]').addEventListener('click', () => {
console.log('用户点了“男”这一整块区域');
});
不过注意:这属于“用户交互起点”,不是 DOM 状态变更信号;如果后续逻辑依赖 checked 值,仍建议以 change 为准。
真正需要 focus 事件的场景极少,多数时候是混淆了“被点击”和“被聚焦”。别为了绑定 onfocus 去改 tabindex、补一堆可访问性逻辑——先确认你要响应的到底是用户操作,还是浏览器焦点管理行为。


















