iter(g248): 补配方 14 标签筛选条联动表格

This commit is contained in:
HIsheR
2026-10-26 22:04:19 +08:00
parent 64289b59ca
commit 0715131a70
3 changed files with 69 additions and 0 deletions
+34
View File
@@ -2780,6 +2780,40 @@ form({
- **半截状态别提交**:`form` 的 `required` 依赖各自 `value` 信号,日期没选时提交会被拦下并定位到该字段;不要自己写 `if (!day()) return` 之类的旁路判断。 - **半截状态别提交**:`form` 的 `required` 依赖各自 `value` 信号,日期没选时提交会被拦下并定位到该字段;不要自己写 `if (!day()) return` 之类的旁路判断。
- 需要区间就用 `datePicker({ range: true })` + 两个 `timePicker`(起 / 止),拼装时各自独立,别指望一个信号同时表达两端。 - 需要区间就用 `datePicker({ range: true })` + 两个 `timePicker`(起 / 止),拼装时各自独立,别指望一个信号同时表达两端。
## 配方 14:标签筛选条 → 表格联动
```ts
import { computed, signal } from '@ui-arch/frame';
import { button, dataTable, inputTag, select, space } from '@ui-arch/ui';
const tags = signal<string[]>(['本地推理']); // 条件条:可增删的多个标签(「且」关系)
const city = signal('all'); // 地区:单值下拉,all 表示不限
const rows = signal(listFromApi()); // 全量数据集(轮询 / 搜索时整体替换)
// 派生行集合:信号一变就重算,直接喂给表格的信号数据源
const matched = computed(() =>
rows().filter((row) =>
(city() === 'all' || row.city === city()) &&
tags().every((need) => row.tags.includes(need)), // 多标签是「且」:逐条都要命中
),
);
space({ gap: 'sm' }, [
inputTag({ value: tags, max: 5, placeholder: '按标签筛选,回车添加' }),
select({ value: city, options: [{ value: 'all', label: '全部地区' }, { value: 'sh', label: '上海' }] }),
button({ label: '重置', variant: 'ghost', onClick: () => { tags([]); city('all'); } }),
]);
const table = dataTable({ data: matched, columns, pageSize: 10 }); // 信号数据源:换源不重置排序与页码
```
要点:
- **筛选在信号层做,不在表格里做**:`dataTable` 的工具栏筛选是「关键字单列」的轻量搜索,多条件组合交给 `computed` 派生行集合,表格只负责渲染当前结果。
- **给表格传信号而不是数组**:`data: matched`(`Computed<T[]>` 同样是 `Signal<T[]>`)换源时内核保留排序、每页行数、当前页,并按 `rowKey` 剔除已消失行的选中态——手写 `replaceChildren(dataTable(...))` 会把这些状态全部丢掉。
- **条件条本身就是一个受控信号集合**:`inputTag` 的 `value` 就是唯一数据源,删除 chip 与增删条件走同一出口,别在业务层再存一份「当前条件」。
- **「且」还是「或」写在派生里**:`every` 是且(收窄)、`some` 是或(放大),两种语义只差一个方法调用,但决定了空条件时的行为——空数组 `every` 恒为真(等于不限),`some` 恒为假(等于无结果),重置逻辑据此写。
- 结果为空时不要另写空状态:`dataTable` 已内置空行提示,筛选无命中会自己显示「没有匹配的行」。
## 通用约定 ## 通用约定
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。 - 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。
+1
View File
@@ -168,3 +168,4 @@
- 配方 11:数据看板筛选区(区间滑块 + 日期预设 + 分组下拉)(3 条要点) - 配方 11:数据看板筛选区(区间滑块 + 日期预设 + 分组下拉)(3 条要点)
- 配方 12:命令面板(⌘K 全局操作入口)(6 条要点) - 配方 12:命令面板(⌘K 全局操作入口)(6 条要点)
- 配方 13:预约时点(日期 + 时间两段拼装)(5 条要点) - 配方 13:预约时点(日期 + 时间两段拼装)(5 条要点)
- 配方 14:标签筛选条 → 表格联动(5 条要点)
+34
View File
@@ -293,6 +293,40 @@ form({
- **半截状态别提交**:`form` 的 `required` 依赖各自 `value` 信号,日期没选时提交会被拦下并定位到该字段;不要自己写 `if (!day()) return` 之类的旁路判断。 - **半截状态别提交**:`form` 的 `required` 依赖各自 `value` 信号,日期没选时提交会被拦下并定位到该字段;不要自己写 `if (!day()) return` 之类的旁路判断。
- 需要区间就用 `datePicker({ range: true })` + 两个 `timePicker`(起 / 止),拼装时各自独立,别指望一个信号同时表达两端。 - 需要区间就用 `datePicker({ range: true })` + 两个 `timePicker`(起 / 止),拼装时各自独立,别指望一个信号同时表达两端。
## 配方 14:标签筛选条 → 表格联动
```ts
import { computed, signal } from '@ui-arch/frame';
import { button, dataTable, inputTag, select, space } from '@ui-arch/ui';
const tags = signal<string[]>(['本地推理']); // 条件条:可增删的多个标签(「且」关系)
const city = signal('all'); // 地区:单值下拉,all 表示不限
const rows = signal(listFromApi()); // 全量数据集(轮询 / 搜索时整体替换)
// 派生行集合:信号一变就重算,直接喂给表格的信号数据源
const matched = computed(() =>
rows().filter((row) =>
(city() === 'all' || row.city === city()) &&
tags().every((need) => row.tags.includes(need)), // 多标签是「且」:逐条都要命中
),
);
space({ gap: 'sm' }, [
inputTag({ value: tags, max: 5, placeholder: '按标签筛选,回车添加' }),
select({ value: city, options: [{ value: 'all', label: '全部地区' }, { value: 'sh', label: '上海' }] }),
button({ label: '重置', variant: 'ghost', onClick: () => { tags([]); city('all'); } }),
]);
const table = dataTable({ data: matched, columns, pageSize: 10 }); // 信号数据源:换源不重置排序与页码
```
要点:
- **筛选在信号层做,不在表格里做**:`dataTable` 的工具栏筛选是「关键字单列」的轻量搜索,多条件组合交给 `computed` 派生行集合,表格只负责渲染当前结果。
- **给表格传信号而不是数组**:`data: matched`(`Computed<T[]>` 同样是 `Signal<T[]>`)换源时内核保留排序、每页行数、当前页,并按 `rowKey` 剔除已消失行的选中态——手写 `replaceChildren(dataTable(...))` 会把这些状态全部丢掉。
- **条件条本身就是一个受控信号集合**:`inputTag` 的 `value` 就是唯一数据源,删除 chip 与增删条件走同一出口,别在业务层再存一份「当前条件」。
- **「且」还是「或」写在派生里**:`every` 是且(收窄)、`some` 是或(放大),两种语义只差一个方法调用,但决定了空条件时的行为——空数组 `every` 恒为真(等于不限),`some` 恒为假(等于无结果),重置逻辑据此写。
- 结果为空时不要另写空状态:`dataTable` 已内置空行提示,筛选无命中会自己显示「没有匹配的行」。
## 通用约定 ## 通用约定
- 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。 - 状态一律放信号(`signal` / `computed`),组件只读写信号,不持有业务数据副本。