单选按钮组必须使用统一的name属性(如name="plan")才能实现互斥;value应使用语义化标识符(如value="basic-monthly")而非价格字符串;必须显式设置checked默认项;label须正确包裹或关联radio以保障可访问性。

单选按钮组的 name 属性必须一致才能互斥
浏览器只靠 name 值识别一组单选按钮(<input type="radio">)是否互斥。如果漏写、拼错或动态生成时 name 不统一,用户就能同时选中多个——这在价格套餐页里是严重逻辑错误。
实操建议:
- 所有套餐选项用同一个
name="plan"(或其他语义化名称,如name="subscription-tier"),不能按价格或 ID 分散命名 - 服务端接收时也只取
plan这一个字段,无需遍历多个参数 - Vue/React 等框架中,绑定的 v-model / value 仍需确保底层 input 的
name一致,否则表单提交行为异常
value 值要存后端可识别的标识,别直接放价格字符串
很多人习惯把 value="¥99/月" 或 value="99" 写进 radio,这会导致两个问题:一是价格格式变化(如加税、换币种)时前端硬编码全崩;二是后端无法区分“99元基础版”和“99元年付折扣版”。
正确做法是用简短、稳定、无歧义的标识符:
-
value="basic-monthly"、value="pro-annual"—— 语义清晰,便于日志追踪和 A/B 测试 - 价格、周期、权益等展示文案全部由前端根据 value 查配置表或映射对象渲染,不耦合在 HTML 中
- 避免用数字 ID(如
value="1"),除非后端已约定好且永不变更
默认选中项必须显式设置 checked,别依赖第一个元素
HTML 规范不保证浏览器自动选中第一个 <input type="radio">。没设 checked 的 radio 组在页面加载后可能全未选中,导致提交空值或触发校验失败。
尤其注意以下场景:
- 服务端渲染时,需根据用户历史选择或策略(如新用户推推荐套餐)动态插入
checked - 纯静态页面至少给推荐档位(如中间档)加上
checked,例如:<input type="radio" name="plan" value="pro-monthly" checked> - JavaScript 动态控制选中状态时,不要只改
element.checked = true,还得同步触发change事件供监听逻辑捕获
无障碍与点击体验:label 必须包裹或关联 radio
只点小圆圈很难操作,尤其在移动端。若 <label></label> 没正确绑定,屏幕阅读器无法朗读选项含义,触控区域也仅限于像素级的按钮本身。
两种合法写法(任选其一):
- 包裹式:
<label><input type="radio" name="plan" value="basic-monthly"> 基础版 ¥68/月</label> - for/id 关联式:
<input id="plan-basic" type="radio" name="plan" value="basic-monthly"><label for="plan-basic">基础版 ¥68/月</label> - 禁止只写文字不套 label,也禁止 label 里只放 span 而不包含 input 或用 for 关联
样式上可通过 label:hover 或 input:focus + label 提升反馈,但核心是语义结构先立住。
价格套餐页的复杂点不在布局,而在于 value 设计是否经得起运营迭代、name 是否真能约束互斥、以及默认态是否对业务逻辑安全。这三个地方松动,后面所有 JS 校验和 UI 动效都只是补丁。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











