iter: d19 dataTable 选中态受控
This commit is contained in:
@@ -200,6 +200,14 @@
|
||||
"acceptance": "checkSkinCss():skin-dom 类型包里所有 .css 出现 #hex 字面量即报错并指出文件行号;5 处 #fff 改为 var(--ua-color-bg)(信号色底上的反色,暗色自动翻转);负向测试(临时加 .ua-tmp{color:#fff})能拦下,移除后回归全绿;AGENTS.md 门禁说明同步;npm run check 全绿",
|
||||
"status": "done",
|
||||
"notes": "rgba(...) 未禁:仅用于阴影与遮罩透明度叠加,不承载品牌色,禁掉会逼出更难读的写法(已在函数注释写明边界);实现上先随 python 写文件把正则转义搞坏两次,改用编辑工具直写并做负向验证确认门禁真实生效"
|
||||
},
|
||||
{
|
||||
"id": "d19",
|
||||
"title": "dataTable 选中态受控(selected 信号)",
|
||||
"motivation": "选中集只在内核里,外部拿不到也无法预设,批量操作/清空选择只能靠内部工具栏;与 page 受控桥接形成对称能力",
|
||||
"acceptance": "DataTableProps 新增 selected?: Signal<RowKey[]>,与内核选择双向同步(内容比较避免来回派发,外部数组拷贝保护内核);demo 首表传 picked 信号,展示已选计数与「清空选择」按钮;manifest/文档/llms-full.txt 同步;npm run check 全绿",
|
||||
"status": "done",
|
||||
"notes": "复用 page 桥接的同一套思路:两个 effect 各管一向,sameKeys 内容比较收敛;内部写回拷贝 [...internal],防外部改动内核数组;demo 需 import type { RowKey } 才能对齐 Signal 的逆变"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+8
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "ui-arch-registry-index/0.1",
|
||||
"generatedAt": "2026-10-23T09:00:48.440Z",
|
||||
"generatedAt": "2026-10-23T09:01:45.831Z",
|
||||
"repoRoot": ".",
|
||||
"packages": [
|
||||
{
|
||||
@@ -1253,6 +1253,11 @@
|
||||
"n": "loading",
|
||||
"t": "boolean | Signal<boolean>",
|
||||
"d": "加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy"
|
||||
},
|
||||
{
|
||||
"n": "selected",
|
||||
"t": "Signal<RowKey[]>",
|
||||
"d": "受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写"
|
||||
}
|
||||
],
|
||||
"example": "dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓名', sortable: true }], pageSize: 5 })",
|
||||
@@ -1266,7 +1271,8 @@
|
||||
"工具栏输入框即筛选,输入即时过滤并回第 1 页;无匹配时显示空状态行",
|
||||
"表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供",
|
||||
"数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复",
|
||||
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用"
|
||||
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用",
|
||||
"需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
@@ -23,3 +23,4 @@
|
||||
{"time": "2026-10-23T16:58:51+08:00", "id": "d16", "result": "done", "summary": "dataTable 消费内核列宽 width:colgroup 固定像素 / flex 自适应,选择列 44px;demo 三列演示宽档;manifest/llms 同步,check 全绿"}
|
||||
{"time": "2026-10-23T16:59:46+08:00", "id": "d17", "result": "done", "summary": "表单错误态打通包裹式控件:focusout/change 取代 blur + aria-invalid + .ua-invalid 后代选择器覆盖 select/radio/slider;demo 加必填 select;check 全绿"}
|
||||
{"time": "2026-10-23T17:00:55+08:00", "id": "d18", "result": "done", "summary": "ua verify 新增皮肤硬编码颜色门禁(#hex 禁止,rgba 仅限阴影/遮罩),清掉 ui.css 5 处 #fff 改令牌;负向测试确认能拦;check 全绿"}
|
||||
{"time": "2026-10-23T17:01:46+08:00", "id": "d19", "result": "done", "summary": "dataTable 新增 selected 受控信号:与内核选择双向同步(内容比较 + 拷贝保护),demo 展示已选计数与清空;check 全绿"}
|
||||
|
||||
+13
-1
@@ -30,6 +30,7 @@ import {
|
||||
toast,
|
||||
tooltip,
|
||||
} from '@ui-arch/ui';
|
||||
import type { RowKey } from '@ui-arch/ui';
|
||||
|
||||
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随) ***/
|
||||
function buildToc(toc: HTMLElement, content: HTMLElement): void {
|
||||
@@ -109,6 +110,9 @@ const tags = signal(['设计', '前端', '组件库']);
|
||||
// —— 滑块:音量与禁用态演示 ——
|
||||
const volume = signal(40);
|
||||
|
||||
// —— 受控选中:dataTable 内部勾选实时写回,外部可清空 ——
|
||||
const picked = signal<RowKey[]>([]);
|
||||
|
||||
// —— 表格加载态:切换后数据行变骨架行,筛选与翻页临时禁用 ——
|
||||
const tableLoading = signal(false);
|
||||
|
||||
@@ -392,7 +396,15 @@ const content = h(
|
||||
{ key: 'city', header: '城市', align: 'center', width: 'flex' },
|
||||
],
|
||||
pageSize: 5,
|
||||
}), h('div', { class: 'row' }, switchButton({ label: '加载态', checked: tableLoading }))),
|
||||
selected: picked,
|
||||
}), h(
|
||||
'div',
|
||||
{ class: 'row' },
|
||||
switchButton({ label: '加载态', checked: tableLoading }),
|
||||
badge({ label: '受控选中', variant: 'default' }),
|
||||
h('span', { class: 'out' }, () => `已选 ${picked().length} 行`),
|
||||
button({ label: '清空选择', variant: 'ghost', onClick: () => picked([]) }),
|
||||
)),
|
||||
card(
|
||||
{ title: '独立分页器联动(pageSize 3,共用页码信号)' },
|
||||
dataTable({
|
||||
|
||||
+3
-1
@@ -1,6 +1,6 @@
|
||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||
|
||||
> 自动生成于 2026-10-23T09:00:48.440Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 自动生成于 2026-10-23T09:01:45.831Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||
|
||||
## 快速上手
|
||||
@@ -695,6 +695,7 @@ const name = signal(''); const f = form({ onSubmit: submit }, [formItem({ label:
|
||||
- selectable(默认 false):boolean —— 启用行选择列:全选三态(含半选)、行 checkbox、已选计数;缺省 false
|
||||
- page:Signal<number> —— 受控页码信号:与内核分页双向同步,传同一个信号给独立 pagination 组件即可联动
|
||||
- loading:boolean | Signal<boolean> —— 加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy
|
||||
- selected:Signal<RowKey[]> —— 受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写
|
||||
|
||||
示例:
|
||||
|
||||
@@ -714,6 +715,7 @@ dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓
|
||||
8. 表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供
|
||||
9. 数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复
|
||||
10. 需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用
|
||||
11. 需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)
|
||||
|
||||
现场演示:apps/docs/demo.html#sec-table
|
||||
|
||||
|
||||
@@ -60,6 +60,20 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
|
||||
});
|
||||
}
|
||||
|
||||
// —— 受控选中桥接:外部信号 ↔ 内核选择集;比较内容而非引用,避免来回派发 ——
|
||||
if (props.selected) {
|
||||
const selSig = props.selected;
|
||||
const sameKeys = (a: RowKey[], b: RowKey[]): boolean => a.length === b.length && a.every((k, i) => k === b[i]);
|
||||
effect(() => {
|
||||
const external = selSig();
|
||||
if (!sameKeys(external, state().selection)) table.dispatch({ type: 'setSelection', keys: external }); // 外部改写 → 内核
|
||||
});
|
||||
effect(() => {
|
||||
const internal = state().selection;
|
||||
if (!sameKeys(internal, selSig())) selSig([...internal]); // 内部勾选 → 写回外部(拷贝避免外部改到内核数组)
|
||||
});
|
||||
}
|
||||
|
||||
const filterKey = props.filterKey ?? props.columns[0].key;
|
||||
const colspan = props.columns.length + (selectable ? 1 : 0);
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ export interface DataTableProps<T> {
|
||||
selectable?: boolean; // 是否启用行选择列(含全选三态与已选计数);缺省 false
|
||||
page?: Signal<number>; // 受控页码信号:与内核分页双向同步,可接独立 pagination 组件联动
|
||||
loading?: boolean | Signal<boolean>; // 加载态:为真时数据行换成骨架行,筛选与翻页禁用
|
||||
selected?: Signal<RowKey[]>; // 受控选中行信号:与内核选择双向同步,供批量操作读取
|
||||
}
|
||||
|
||||
/*** 选项条目:select / radioGroup / tabs 共用的选项形状 ***/
|
||||
|
||||
@@ -1124,6 +1124,11 @@
|
||||
"n": "loading",
|
||||
"t": "boolean | Signal<boolean>",
|
||||
"d": "加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy"
|
||||
},
|
||||
{
|
||||
"n": "selected",
|
||||
"t": "Signal<RowKey[]>",
|
||||
"d": "受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写"
|
||||
}
|
||||
],
|
||||
"example": "dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓名', sortable: true }], pageSize: 5 })",
|
||||
@@ -1137,7 +1142,8 @@
|
||||
"工具栏输入框即筛选,输入即时过滤并回第 1 页;无匹配时显示空状态行",
|
||||
"表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供",
|
||||
"数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复",
|
||||
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用"
|
||||
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用",
|
||||
"需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)"
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user