## 47 · 表格 Table ### 47.1 用途 把多条同构记录按列并排,用于「订单列表 / 库存明细 / 对账单」这类需要**逐行横向对比**的场合;移动端与桌面端的关键差别是**宽度根本不够**:桌面上 8 列一眼看完,375px 的手机上同样 8 列每列只剩 47px,文字全部折断。因此移动端表格必须做「**在组件自己的容器里横向滚动**」——**绝不能让页面整体横向溢出**,否则整页会跟着左右晃、顶栏与底部栏一起位移;列更多或更该读字段名时改用 `mode=card`,把每行摊成键值对,彻底不需要横滚。 ### 47.2 结构(anatomy) - `table`:根元素,纵向排列「视口 + 空态」 - `table__viewport`:**横向滚动的唯一发生点**(`overflow-x: auto`),页面整体不横向溢出 - `table__inner`:原生 `table`,`min-width` 由 `--kole-m-table-min-width` 给出;超过容器即滚 - `table__caption`:可选表格标题(说明这张表在讲什么) - `table__head` / `table__head-cell`:表头与表头单元格,`position: sticky` 固定在滚动视口顶部 - `table__row` / `table__cell`:数据行与单元格,行高不小于 44px;单元格可带 `data-label`(卡片模式的字段名来源) - `table__empty`:空态占位,`role="status"` + `aria-live="polite"` ### 47.3 变体维度 - `mode`:`scroll`(横向滚动,列多时用)/ `card`(每行摊成键值对,小屏彻底不横滚) - `size`:`default`(常规行高)/ `compact`(收紧内边距与字号;行高仍不小于 44px) - `stripe`:`false`(纯白底)/ `true`(偶数行浅底,便于横向扫读时对齐行) - `bordered`:`false`(只有横线)/ `true`(单元格之间也有竖线) ### 47.4 状态 - default:常态 - selected:当前选中行,`is-selected` 与 `aria-selected` 同步(行选中不是复选框,单行高亮即可) - disabled:整行置灰且不响应,写 `aria-disabled="true"` - empty:没有数据时的占位文案(列宽语义不变,不会把容器撑宽) - clickable:行可点(`clickable=true` 时整行都是热区,按下反馈是整行背景变化) ### 47.5 交互与触控 - **横向滚动发生在 `table__viewport` 上**:根与视口都写 `min-width: 0`,否则内部 `min-width` 会把父级顶宽、页面整体横向溢出 - 选项行高不小于 44px;触屏上横向滑动不被父级纵向滚动吞掉(`touch-action: pan-x pan-y`) - 表头用 `position: sticky` 而不是 `fixed`——`fixed` 会脱出滚动容器,横向滚动时表头不跟随 - 长文本列默认单行省略,完整值放 `title`;数字列用等宽字右对齐,便于按位对比 - 点整行即选中(同表互斥);行内的独立控件(按钮 / 链接)要阻止冒泡,避免一次点击触发两个动作 - 行可点时同时提供键盘路径(聚焦后回车 / 空格),不把鼠标点击当成唯一入口 ### 47.6 无障碍 - 用原生 `table` / `thead` / `tbody` / `tr` / `th` / `td`,表头写 `scope="col"`(读屏能报出列名) - 空态用 `role="status"` + `aria-live="polite"` 播报占位文案 - 禁用行写 `aria-disabled="true"`,读屏播报不可用 - **可点行必须同时可聚焦**:`clickable=true` 时行写 `tabindex="0"` + `role="row"` + `aria-selected`,聚焦后回车 / 空格即选中 —— 只有鼠标点击而没有键盘路径是缺陷,不是简化 - 焦点环画在行内第一个单元格上(`tr` 上的 `outline` 在部分浏览器不渲染) - 行内的独立控件(链接 / 按钮)有可见焦点环,并阻止冒泡 - `mode=card` 时字段名由 `data-label` 生成并参与读屏(键值对在视觉与语义上都成立) - 可点行的 `cursor: pointer` 只给表体行:表头行不承载点击,跟着变手型会把「这里能点」这个信号弄错 ### 47.7 doNotInvent - 虚拟滚动与无限加载的触发规则(由宿主容器负责;本组件不接管纵向滚动) - 服务端排序 / 筛选 / 分页(排序图标与请求都由宿主发起) - 列宽拖拽调整与列显隐设置(移动端没有这个操作面) - 冻结列(`position: sticky` 的横向版本;当前只固定表头的纵向位置) ### 47.8 unknowns - 表头是否需要在纵向滚动时也吸顶(当前只在宿主给固定高度时生效) - 行选中是单选还是多选(当前单选;多选应交给 Checkbox 列) - 卡片模式下字段名的排列是「左标签右值」还是「上标签下值」 ---