## 38 · 分段器 Segmented ### 38.1 用途 在 2~5 个**互斥**选项里选一个,并让「当前选的是哪个」一眼可见(订单状态、时间范围、列表/网格视图切换)。移动端与桌面端的关键差别是**没有悬停**:桌面端用户把鼠标移到未选项上就能预览「这里可以点」,触屏上这个预告不存在 —— 所以选中项必须靠**形态**(白底滑块 + 阴影)而非色相区分,且每一项都要占满 44px 高,否则 2~5 个选项挤在一行时手指点不准。 ### 38.2 结构(anatomy) - `segmented`:容器,浅底 + 内边距,横向排列选项;`role="radiogroup"` 并带 `aria-label` 说明这组在选什么 - `item`:单个选项,原生 `button` + `role="radio"`(整项可点、可键盘聚焦),`data-value` 携带取值 - `label`:选项文字(可含装饰图标,图标 `aria-hidden` 由文字承担语义) ### 38.3 变体维度 - `size`:`default`(44px 高)/ `small`(32px 高,卡片内次级筛选用) - `block`:`false`(宽度随内容)/ `true`(占满容器且各项等分) ### 38.4 状态 - default:未选中(透明底 + 次级字色) - selected:选中(`is-active` —— 卡片底滑块 + 品牌字色 + `aria-checked="true"`) - disabled:整段置灰、不响应点击;单个选项也可单独禁用 ### 38.5 交互与触控 - 选项切换是**一次轻点**:点击后该项 `is-active`、同组其它项复位;不响应长按、双击与拖动(横滑切换属于标签栏手势,不在本组件) - 选中态是视觉与属性的**双向同步**:除类名外必须同时更新 `aria-checked`,只改颜色不改属性会被无障碍判为缺口 - 每项热区高 ≥ 44px(`size=small` 时视觉 32px,但**触摸命中区仍按 44px 计**,纵向不留死区) - 选中项再次点击**不重复触发** `change`(值未变不发事件,避免宿主收到同值事件后做无意义的重渲染) - 受控:组件不存值,只回传目标值 `change`;宿主不采纳时视觉不变化 - 切换动效 120ms(`--kole-duration-fast`),`prefers-reduced-motion` 下瞬时切换 ### 38.6 无障碍 - 容器 `role="radiogroup"` + `aria-label`;每个选项原生 `button` + `role="radio"` + `aria-checked` - 选项名称由文字承担;装饰性图标必须 `aria-hidden="true"` - 禁用时容器补 `aria-disabled="true"`,选项用原生 `disabled`(读屏播报不可用,且不进 Tab 序列) - 键盘:Tab 进入分组,左右方向键在选项间移动并选中(原生 radio 组的键盘约定) ### 38.7 doNotInvent - 多选(同时选中多个)—— 需要多选时改用标签组或多选框 - 选项的横向滚动、换行与「更多」折叠(超过 5 个应换组件) - 选中项的下划线滑块动画(那是标签栏的视觉语言,不是分段器) - 选项禁用条件与业务权限的判断 ### 38.8 unknowns - 选项数量上限是否应硬约束在 5 个(当前只写建议,不做运行时拦截) - `size=small` 的命中区是否需要在纵向自动补到 44px(当前靠 `--kole-m-hit-slack` 思路,未在样式中强制) - 是否需要「滑动经过即选中」(当前只认轻点,滑动不选中) ---