## 33 · 单选框 Radio ### 33.1 用途 在一组互斥选项里选且只选一项(支付方式、配送时效、发票类型);移动端与桌面端的关键差别是**选中态的表达**:触屏没有鼠标悬停可以预告状态,选中必须同时有形状差异(圆点内圈实心)与 `aria-checked`,不能只靠颜色;且整行(圆点 + 文字)都是热区,行高不小于 44px。 ### 33.2 结构(anatomy) - `group`:根元素,`role="radiogroup"` + `aria-label` 说明这组在选什么 - `item`:单个选项,整行都是热区(原生 `button` + `role="radio"`) - `icon`:圆点,未选中是空心环、选中是实心圆 + 内圈反色点 - `label`:选项文字,占满剩余宽度 - `desc`:可选说明行,跟在文字下方(如「需先完成企业认证」) - `state`:选中态 `is-checked` 与 `aria-checked` 双写 ### 33.3 变体维度 - `orientation`:`vertical`(纵向排列,组内画分隔线)/ `horizontal`(横向排列,靠间距分组) - `button`:`false`(圆点 + 文字)/ `true`(胶囊标签式,无圆点) ### 33.4 状态 - default:未选中(空心环) - checked:选中(实心圆 + 内圈反色点,`aria-checked="true"`) - disabled:置灰且不可聚焦,读屏播报不可用 ### 33.5 交互与触控 - 整行(圆点 + 文字)都是热区,行高不小于 44px;横向组里每项自身也保持这个边长 - 一次触摸即选中,不需要二次确认;选中后**不能**再点回空值(需要清空由宿主提供额外的「清除」动作) - 互斥由组件负责:选中一项会立即清掉同组其它项的选中态,不留下两个选中 - 切换动效是圆点内圈 150ms 缩放;减少动态偏好下瞬时切换 - 选中后立即触发 change 事件,回传该项的值 ### 33.6 无障碍 - 组用 `role="radiogroup"` + `aria-label` 说明分组名称 - 每项是原生 `button` + `role="radio"` + `aria-checked`(读屏会播报「单选按钮,已选中/未选中」) - 圆点与内圈是纯装饰,对读屏隐藏(`aria-hidden`),语义全靠 `role="radio"` - 禁用项用原生 `disabled` 并补 `aria-disabled="true"` ### 33.7 doNotInvent - 「取消选中」的回到空值交互(单选的语义就是必有一项) - 横向组自动换行的列数策略(由宿主按文案长度决定,组件只负责 flex-wrap) - 与表单一起提交时的隐藏字段(由宿主添加) - 选项内容的异步加载与搜索过滤 ### 33.8 unknowns - 横向组超过一行时是否改成纵向(当前包裹后当行处理) - 圆点尺寸是否随字号一起放大(当前固定 20px) - `desc` 说明行是否允许两行以上(当前单行省略) ---