iter(g331): 新增配方 22 表格行内编辑
This commit is contained in:
@@ -509,6 +509,45 @@ card({ title: '消息中心' },
|
||||
- `relativeTime` 默认每 30 秒自刷新,「3 分钟前」自己会走字;列表重建后新实例接着算,不用手动更新时间文案。条数极多时把 `list` 换 `virtualList`,并把 `refresh` 调大或传 0。
|
||||
- 通知条目要可操作时在 list 的 `onItemClick` 里跳详情或调 `notification`(右下角)补一条带按钮的强提醒;轻提示走 `toast`,别在同一屏堆两层浮层。
|
||||
|
||||
## 配方 22:表格里就地改数据(editable + dataTable)
|
||||
|
||||
场景:后台列表要改一个预算、改一个区域名,不想让用户点进详情页再回来。
|
||||
|
||||
```ts
|
||||
type Row = { id: string; name: string; budget: string };
|
||||
const rows = signal<Row[]>([
|
||||
{ id: 'r1', name: '华东区', budget: '120' },
|
||||
{ id: 'r2', name: '华南区', budget: '95' },
|
||||
]);
|
||||
|
||||
/** 回写单格:只有 editable 的 onCommit 会走到这里,Esc 取消根本不触发,所以取消不会污染数据 */
|
||||
const patch = (id: string, key: 'name' | 'budget', value: string): void => { rows(rows().map((r) => (r.id === id ? { ...r, [key]: value } : r))); }; // 只改这一行这一列
|
||||
|
||||
/** 一格的草稿信号:初值取自行数据,与 rows 解耦——编辑中不会被别处的刷新冲掉 */
|
||||
const cell = (row: Row, key: 'name' | 'budget', title: string) => editable({
|
||||
value: signal(row[key]), // 草稿缓冲,不是数据源
|
||||
label: title,
|
||||
validate: (v) => (v.trim() ? null : `${title}不能为空`), // 与 form 同口径:返回文案即不提交
|
||||
onCommit: (v) => { patch(row.id, key, v); toast.success(`${title}已保存`); },
|
||||
});
|
||||
|
||||
dataTable({
|
||||
data: rows, // 传信号:提交回写后内核整表换源,重建出的格子拿到新草稿
|
||||
columns: [
|
||||
{ key: 'name', header: '区域', width: 200, render: (row) => cell(row, 'name', '区域') }, // render 决定这一格画什么
|
||||
{ key: 'budget', header: '预算(万)', align: 'right', render: (row) => cell(row, 'budget', '预算') },
|
||||
],
|
||||
pageSize: 5,
|
||||
});
|
||||
```
|
||||
|
||||
要点:
|
||||
- 唯一数据源仍是 `rows`:`editable` 里的信号只是草稿缓冲,提交才回写。反过来把草稿当数据源,Esc 取消后表格显示的就是「没保存的值」。
|
||||
- 列的 `render` 只负责画什么,排序 / 筛选 / 导出仍按 `data` 里的原值走——所以行数据保持原始字符串,别为了显示把数据换成 DOM。
|
||||
- 提交会让内核整表换源,正在编辑的另一格草稿会被重建冲掉:一次只编辑一格是行内编辑的合理约束,要并行编辑就把草稿提到 `rows` 之外的状态里自己管。
|
||||
- 校验口径与 `form` 一致:`validate` 返回文案则不提交、保持编辑态并标红(`aria-invalid` + `role=alert`),用户改对再提交即可,不要在回调里弹 toast 了事。
|
||||
- 格内的点击会被拦下,不会触发 `onRowClick`:点输入框不该等于「打开详情」。反过来说,想整行进详情就别把可交互控件铺满整行。
|
||||
- 纯文本列继续用 `format`:它走 `textContent`,天然免注入;`render` 只在真要塞组件(tag / avatar / progress / editable)时才用。
|
||||
## 通用约定
|
||||
|
||||
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
|
||||
|
||||
Reference in New Issue
Block a user