iter(g336): 表格行选择补读屏语义
This commit is contained in:
@@ -61,7 +61,7 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
const span = (): number => shown().length + (selectable ? 1 : 0) + (props.renderDetail ? 1 : 0); // 跨列数随可见列与展开列变化
|
||||
|
||||
// —— 表头全选框:checked / indeterminate 三态跟随当页选中情况 ——
|
||||
const headCheck = h('input', { type: 'checkbox', class: 'ua-checkbox' }) as HTMLInputElement;
|
||||
const headCheck = h('input', { type: 'checkbox', class: 'ua-checkbox', 'aria-label': '全选本页' }) as HTMLInputElement; // 无名字的复选框读屏只念「复选框」
|
||||
headCheck.addEventListener('change', () => {
|
||||
if (headCheck.checked) api.selectAllVisible();
|
||||
else table.dispatch({ type: 'clearSelection' });
|
||||
@@ -137,15 +137,15 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
return h('td', { class: col.align ? `ua-align-${col.align}` : null, onclick: custom ? (e: MouseEvent) => e.stopPropagation() : null }, custom ?? (col.format ? col.format(raw, row) : String(raw))); // 无 render 退回纯文本(免注入);格内点击不触发整行回调
|
||||
});
|
||||
if (selectable) {
|
||||
const check = h('input', { type: 'checkbox', class: 'ua-checkbox' }) as HTMLInputElement; // 受控:选中态由内核 selection 决定
|
||||
const check = h('input', { type: 'checkbox', class: 'ua-checkbox', 'aria-label': `选择第 ${i + 1} 行` }) as HTMLInputElement; // 受控:选中态由内核 selection 决定;名字带行号,读屏才分得清选哪行
|
||||
check.checked = selected;
|
||||
check.addEventListener('change', () => table.dispatch({ type: 'toggleSelect', key }));
|
||||
cells.unshift(h('td', { class: 'ua-cell-check' }, check));
|
||||
}
|
||||
if (props.renderDetail) cells.unshift(expandCell(open, `第 ${i + 1} 行`, () => expanded(open ? expanded().filter((k) => k !== key) : [...expanded(), key]))); // 展开列在最前:与选择列并列但不互斥
|
||||
const rowProps = props.onRowClick // 传了才把整行做成可聚焦按钮语义(Tab 进入、Enter / 空格触发)
|
||||
? { tabindex: '0', class: `ua-row-clickable${selected ? ' ua-row-selected' : ''}`, onclick: () => props.onRowClick?.(row), onkeydown: (e: KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); props.onRowClick?.(row); } } }
|
||||
: selected ? { class: 'ua-row-selected' } : null;
|
||||
? { tabindex: '0', class: `ua-row-clickable${selected ? ' ua-row-selected' : ''}`, 'aria-selected': selectable ? String(selected) : null, onclick: () => props.onRowClick?.(row), onkeydown: (e: KeyboardEvent) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); props.onRowClick?.(row); } } }
|
||||
: selected ? { class: 'ua-row-selected', 'aria-selected': 'true' } : null; // 淡底是视觉,aria-selected 才是读屏能听到的「这行被选中」
|
||||
const tr = h('tr', rowProps, ...cells);
|
||||
return props.renderDetail && open ? [tr, detailRow(span(), props.renderDetail(row))] : [tr];
|
||||
});
|
||||
|
||||
@@ -2055,7 +2055,7 @@
|
||||
"列展示细节用皮肤字段:align 控制表头与单元格对齐,format(value, row) 返回纯文本(走 textContent,不需要转义)",
|
||||
"数据源可以给信号或 computed(如筛选结果):变化时内核整体换源,选择状态按 rowKey 剔除已消失的行,排序与页码不被打断",
|
||||
"列宽用内核字段 width:数字(像素)固定该列,'flex' 或不设则按内容自适应",
|
||||
"selectable: true 开启行选择:表头全选框带 indeterminate 半选态,工具栏显示已选计数",
|
||||
"selectable: true 开启行选择:表头全选框带 indeterminate 半选态(aria-label「全选本页」),每行复选框读「选择第 N 行」、选中行标 aria-selected(淡底只是视觉),工具栏显示已选计数",
|
||||
"选中行用低视觉比重样式(淡色底 + 弱化文字),选择状态存 rowKey,跨页不丢失",
|
||||
"工具栏输入框即筛选,输入即时过滤并回第 1 页;无匹配时显示空状态行",
|
||||
"表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供",
|
||||
|
||||
Reference in New Issue
Block a user