## 34 · 多选框 Checkbox ### 34.1 用途 在一组选项里同时选中任意多项(兴趣标签、订阅范围、筛选维度),并支持「全选」;移动端与桌面端的关键差别是**半选态的表达**:触屏上没有鼠标悬停预告状态,全选行在「部分选中」时必须显示出与「全选 / 全不选」都不同的第三态(横杠),且整行(方框 + 文字)都是热区,行高不小于 44px。 ### 34.2 结构(anatomy) - `group`:根元素,`role="group"` + `aria-label` 说明这组在选什么 - `item`:单个选项,整行都是热区(原生 `button` + `role="checkbox"`) - `icon`:方框,未选中是空心框、选中是品牌底 + 反色勾号、半选是品牌底 + 横杠 - `label`:选项文字,占满剩余宽度 - `desc`:可选说明行,跟在文字下方(如「需先绑定手机号」) - `all`:全选行,不存储自己的状态,由组内各项推导 ### 34.3 变体维度 - `orientation`:`vertical`(纵向排列,组内画分隔线)/ `horizontal`(横向排列,靠间距分组) - `button`:`false`(方框 + 文字)/ `true`(胶囊标签式,无方框) - `selectAll`:`false`(不显示全选行)/ `true`(组首显示全选行) ### 34.4 状态 - default:未选中(空心框) - checked:选中(品牌底 + 反色勾号,`aria-checked="true"`) - indeterminate:半选,只在全选行出现(`aria-checked="mixed"`) - disabled:置灰且不可聚焦,读屏播报不可用 ### 34.5 交互与触控 - 整行(方框 + 文字)都是热区,行高不小于 44px;横向组里每项自身也保持这个边长 - 一次触摸即切换,各项互相独立;不限制同时选中的数量上限 - 点全选行:只要还有未选中项就全部选中,否则全部清空(不在「半选」上停留) - 全选的选中态是**推导值**,不单独存储 —— 单项变化后立即重算,避免出现「全选已勾上但还有一项没选」 - 切换动效是勾号 150ms 缩放;减少动态偏好下瞬时切换 - 每次切换立即触发 change 事件,回传切换后的完整值数组 ### 34.6 无障碍 - 组用 `role="group"` + `aria-label` 说明分组名称 - 每项是原生 `button` + `role="checkbox"` + `aria-checked`(读屏会播报「复选框,已选中/未选中」) - 全选行的半选态用 `aria-checked="mixed"`(checkbox 角色允许的第三个值) - 方框与勾号是纯装饰,对读屏隐藏(`aria-hidden`),语义全靠 `role="checkbox"` - 禁用项用原生 `disabled` 并补 `aria-disabled="true"` ### 34.7 doNotInvent - 「最多选 N 项」的数量上限与超出提示(业务规则在宿主) - 分组嵌套(一组里再分组)的层级表达 - 与表单一起提交时的隐藏字段(由宿主添加) - 选项内容的异步加载与「已选 N 项」的汇总条 ### 34.8 unknowns - 全选行是否显示「已选 2/5」这类计数 - 半选态在非全选行上的用例(如父级节点) - 胶囊按钮式是否也需要禁用态的视觉层(当前复用同一条置灰规则) ---