ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

TanStack Angular Table 全局过滤(Global Filtering)完整指南:特性注册、状态管理与服务端/客户端方案

TanStack Angular Table 全局过滤(Global Filtering)完整指南:特性注册、状态管理与服务端/客户端方案 TanStack Angular Table 全局过滤Global Filtering完整指南特性注册、状态管理与服务端/客户端方案【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table全局过滤Global Filtering是 TanStack Table 中跨所有列执行统一搜索的核心能力本指南以tanstack/angular-table在 Angular 环境下的官方文档docs/framework/angular/guide/global-filtering.md为骨架结合仓库内table-core的过滤实现源码与 Angular 官方示例系统讲解全局过滤的完整接入流程。读完本文你将掌握如何注册过滤特性并正确启用客户端/服务端过滤、如何使用内置与自定义globalFilterFn、如何通过外部 Atom 或 Angular signal 掌控过滤状态、如何把搜索输入框接入表格以及禁用与排查全局过滤的 API 用法。前置准备注册过滤相关特性全局过滤在特性层面依赖列过滤Column Filtering因此必须先注册columnFilteringFeature再注册globalFilteringFeature。若使用客户端过滤还需在特性之后挂载filteredRowModel: createFilteredRowModel()——因为 row model 槽位是类型检查的顺序错误会导致类型错误。整个特性配置通过tableFeatures聚合器传入injectTableimport { signal } from angular/core import { injectTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, createFilteredRowModel, filterFn_includesString, } from tanstack/angular-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, filteredRowModel: createFilteredRowModel(), // if using client-side filtering // manualFiltering: true, // if using manual server-side filtering filterFns: { includesString: filterFn_includesString }, }) export class App { readonly data signal(defaultData) readonly table injectTable(() ({ features, columns, data: this.data(), })) }关于filterFns注册表的打包优化上面的filterFns注册表只列出了该表实际用到的内置过滤函数。虽然也可以直接展开整个内置注册表filterFns: { ...filterFns }但这样做会把所有内置过滤函数打进产物包破坏 tree-shaking。从源码 filterFns.ts 可以看到内置注册表filterFns对象本身带有deprecated标注官方建议按需引入单个filterFn_*函数并只注册用到的那些或者干脆不注册直接把函数传给globalFilterFn/ 列级filterFn选项。需要说明的是table-core的完整内置注册表实际包含 18 个过滤函数除了下文的 12 个之外还有empty、notEmpty、startsWith、endsWith、equalsStringSensitive、inDateRange等官方指南中列出的 12 个是全局过滤最常用的内置函数。injectTable的响应式工作方式injectTable接受一个 options 工厂函数injectTable.ts 中将它包进computed每当工厂内部读取的任何 signal 变化时就会重新求值并通过setOptions同步到表格实例这正是 Angular 适配器与响应式模型保持同步的机制。因此建议把columns、特性配置、row model 等昂贵/静态的值放在工厂函数外部保持稳定引用只在工厂内部读取data()、过滤/分页/排序等响应式状态。客户端过滤 vs 服务端过滤先做决策过滤应当与排序、分页作用于同一份数据集。TanStack Table 官方给出的决策框架是客户端过滤浏览器持有完整数据集时使用。过滤、排序、分页全部在本地完成交互即时。服务端过滤浏览器只持有单页或其他子集时使用此时数据应由服务端按过滤条件下发。除非你有意只过滤当前已加载的行否则不应在子集上做客户端过滤。完整的决策框架、性能考量以及数据操作组合建议参见 客户端 vs 服务端指南。客户端过滤的行模型与页码自动重置客户端过滤行模型createFilteredRowModel在全局过滤输入变化时还会触发页码自动重置钩子page-index auto-reset hook。从 createFilteredRowModel.ts 的源码可以看到它把columnFilters与globalFilter两个状态切片作为 memo 依赖并在更新后通过onAfterUpdate: skipFirstRun(() table_autoResetPageIndex(table))调用table_autoResetPageIndex。页码是否真的重置取决于autoResetPageIndex、autoResetAll与manualPagination三个选项的取值。如果过滤是手动的manual且这个行模型被省略或绕过全局过滤状态变化就不会触发该钩子此时如果使用服务端分页需要在过滤变化的处理函数里手动重置分页。手动服务端全局过滤Manual Server-Side如果你决定用服务端全局过滤取代内置的客户端过滤做法如下不需要filteredRowModel。传给表格的data应当是服务端已经过滤好的数据。但如果你在 features 中已经添加了filteredRowModel可以通过把manualFiltering选项设为true让表格跳过它import { injectTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, } from tanstack/angular-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature }) readonly table injectTable(() ({ features, data, columns, manualFiltering: true, }))[!NOTE] 使用手动全局过滤时本指南后续讨论的许多选项将不起作用。当manualFiltering为true表格实例不会对传入的行应用任何全局过滤逻辑而是假定行已被过滤按传入的data原样使用。在服务端方案下globalFilter状态本身仍然很有价值——它可以作为请求参数或查询 key 的一部分把搜索词发送给后端详见下文全局过滤状态一节。客户端全局过滤Client-Side使用内置的客户端全局过滤时在 features 中加入globalFilteringFeature以及它必需的columnFilteringFeature前置依赖和filteredRowModel工厂即可import { injectTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, createFilteredRowModel, filterFn_includesString, } from tanstack/angular-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, filteredRowModel: createFilteredRowModel(), filterFns: { includesString: filterFn_includesString }, }) readonly table injectTable(() ({ features, // other options... }))底层过滤流程从 createFilteredRowModel.ts 的实现可以看到客户端全局过滤的完整链路空过滤值undefined/null/会整体跳过过滤直接返回预过滤行模型解析列过滤与全局过滤函数其中全局过滤函数通过table_getGlobalFilterFn(table)解析函数直接返回、auto委托给includesString、字符串从filterFns注册表查找见 globalFilteringFeature.utils.ts用column_getCanGlobalFilter筛出所有可全局过滤的叶子列对每一列都执行一次全局过滤函数并给行打上__global__标记——任意一列命中即为保留行命中即break最后通过filterRows综合列过滤与全局过滤结果横向过滤每一行。这就是全局过滤 一个搜索词作用于所有允许过滤的列的实现本质。全局过滤函数globalFilterFnglobalFilterFn选项决定全局过滤所用的过滤函数。它可以是一个字符串引用注册在tableFeatures的filterFns槽位中的内置或自定义过滤函数也可以直接传一个函数readonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features data, columns, globalFilterFn: includesString, // built-in filter function }))12 个内置过滤函数默认情况下有 12 个内置过滤函数可选函数名行为说明includesString不区分大小写的字符串包含匹配全局过滤的默认值includesStringSensitive区分大小写的字符串包含匹配equalsString不区分大小写的字符串相等equals严格相等weakEquals宽松相等arrIncludes行的数组或字符串值包含过滤值中的至少一个arrIncludesAll行的数组值包含每一个过滤值arrIncludesSome行的数组值包含过滤值中的至少一个arrHas行的标量值等于过滤值中的至少一个inNumberRange闭区间[min, max]数字范围端点会归一化若反向则自动交换between开区间 min/max 范围空端点视为开放betweenInclusive闭区间 min/max 范围空端点视为开放以默认的includesString为例filterFns.ts 中它的实现通过resolveFilterValue/resolveDataValue把过滤值与单元格数据统一String(...).toLowerCase()后再做includes比较——这就是不区分大小写的来源。inNumberRange则会先把端点parseFloat归一化反向端点自动交换并且明确拒绝非数字行值null、、布尔值等不会因 JS 宽松关系强转而混入区间。你也可以定义自己的自定义全局过滤函数并直接传给globalFilterFn选项详见下文自定义全局过滤函数。全局过滤状态Global Filter StateglobalFilter状态切片保存当前的全局过滤值通常是一个搜索字符串切片类型为any以便自定义全局过滤函数接受其他形状的值。在 Angular 中读取方式是table.atoms.globalFilter.get()——表格的 atom 读取就是 signal 读取在模板表达式、computed(...)或effect(...)中读取会自动追踪更新。方式一外部 Atomv9 推荐如果需要在表格之外访问全局过滤状态官方推荐在 v9 中使用外部 Atom用tanstack/angular-store的createAtom创建并通过atoms表格选项传入。Atom 保留细粒度的订阅过滤值可以被其他位置例如服务端过滤的查询 key直接使用而无需在每次变化时重新执行injectTable的 options 初始化器import { createAtom } from tanstack/angular-store export class App { readonly globalFilterAtom createAtomstring() readonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features // other options... atoms: { globalFilter: this.globalFilterAtom, // table.setGlobalFilter now updates globalFilterAtom }, })) // read the atom wherever you need the value (e.g. for a query key) // this.globalFilterAtom.get() }注意一旦通过atoms.globalFilter传入外部 Atomtable.setGlobalFilter更新的是这个 Atom 的值外部即可实时读取。方式二v8 风格受控状态Angular signalv8 风格的state.globalFilteronGlobalFilterChange模式仍然受支持。在 Angular 中这意味着用一个 Angular signal 来持有切片如下面 Basic External State 示例 所示readonly globalFilter signalstring() readonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features // other options... state: { globalFilter: this.globalFilter(), }, onGlobalFilterChange: (updater) typeof updater function ? this.globalFilter.update(updater) : this.globalFilter.set(updater), }))这种模式适合简单集成或从 v8 迁移的代码但它不如外部 Atom 细粒度。两者的深入对比参见 表格状态指南。在 UI 中添加全局过滤输入框TanStack Table不会自动渲染全局过滤输入框需要手动在 UI 中添加入口。典型做法是在表格上方放一个搜索输入框用table.atoms.globalFilter.get()响应式读取当前值用table.setGlobalFilter更新它input typetext [value]table.atoms.globalFilter.get() ?? (input)table.setGlobalFilter($any($event.target).value) placeholderSearch all columns... /更完整的实战形态可以参考仓库里的 filters-fuzzy 示例模板它使用了一个debouncedInput指令对输入做 500ms 防抖再通过(changeEvent)回调调用table.setGlobalFilter配合for渲染表头与行是全局过滤 分页 排序组合的完整样板。对应的组件逻辑见 filters-fuzzy 示例入口。自定义全局过滤函数如果需要自定义全局过滤逻辑定义一个过滤函数并传给globalFilterFn选项即可。函数签名接收(row, columnId, filterValue)返回布尔值表示该行是否应保留const customFilterFn (row, columnId, filterValue) { return // true if the row should be included in the filtered rows } readonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features // other options... globalFilterFn: customFilterFn, }))[!NOTE] 一个非常流行的做法是用模糊匹配fuzzy函数做全局过滤这已在 模糊过滤指南 中完整讨论。仓库的 filters-fuzzy 示例 就是现成范例它借助tanstack/match-sorter-utils的rankItem实现fuzzyFilter通过addMeta把RankingInfo写入行的columnFiltersMeta再返回itemRank.passed将其注册到filterFns: { fuzzy: fuzzyFilter }并通过globalFilterFn: fuzzy启用同时用compareItems实现fuzzySort让命中行按匹配度排序。可对照 模糊过滤指南 阅读其完整代码。初始全局过滤状态Initial State如果希望在表格初始化时就带有一个全局过滤值可以把该状态放进initialState选项。但如果你自己掌控了这个切片外部 Atom 或 Angular signal就应该在 Atom/signal 上设置起始值而不是initialStatereadonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features // other options... initialState: { globalFilter: search term, // if not controlling globalFilter state, set initial state here }, }))[!NOTE]不要同时使用initialState.globalFilter和受控的globalFilter通过atoms或state因为受控值会覆盖initialState.globalFilter。禁用全局过滤默认情况下所有列都参与全局过滤。可以通过以下方式控制列级在列定义中设置enableGlobalFilter: false仅关闭该列的全局过滤表级在表格选项中设置enableGlobalFilter: false关闭所有列的全局过滤总开关把enableFilters设为false同时关闭列过滤与全局过滤。const columns [ { header: () Id, accessorKey: id, enableGlobalFilter: false, // disable global filtering for this column }, //... ] //... readonly table injectTable(() ({ features, // filteredRowModel and filterFns are registered in features // other options... columns, enableGlobalFilter: false, // disable global filtering for all columns }))禁用全局过滤后该列的column.getCanGlobalFilterAPI 会返回false。getCanGlobalFilter的判定逻辑从源码 globalFilteringFeature.ts 与 globalFilteringFeature.utils.ts 可以看到一个列参与全局过滤需要同时满足以下条件列定义enableGlobalFilter默认true未被列级关闭表格选项enableGlobalFilter默认true未被表级关闭表格选项enableFilters默认true未被总开关关闭可选的getColumnCanGlobalFilter回调返回true该列存在accessorFn即列可取值。默认的getColumnCanGlobalFilter还会检查列首行值是否为string或number类型——这解释了为什么对象值或undefined列默认不参与全局过滤。示例 filters-fuzzy 入口 的注释里也给出了getColumnCanGlobalFilter: column column.id ! status这种把单列排除在全局过滤之外的用法。全局过滤 API 速查以下 API 在接入全局过滤 UI 时最常用API作用table.setGlobalFilter设置全局过滤值适合接到搜索输入框的input事件处理器table.resetGlobalFilter把全局过滤值重置为初始状态传truetable.resetGlobalFilter(true)则忽略初始状态、清空为undefinedtable.getGlobalFilterFn返回当前实际使用的全局过滤函数用户自定义或自动解析后的结果table.getGlobalAutoFilterFn返回默认的全局过滤函数目前是includesStringcolumn.getCanGlobalFilter返回该列是否参与全局过滤常用于调试哪些列会被搜索其中setGlobalFilter与resetGlobalFilter的实现细节也值得了解table_setGlobalFilter直接把 updater 交给onGlobalFilterChangeglobalFilteringFeature.utils.tsupdater 既可以是新值也可以是接收旧值返回新值的函数Angular 适配器会把它路由到表格自己的状态管理器或你传入的外部 Atom / signalresetGlobalFilter在默认情况下cloneState(table.initialState.globalFilter)传true则重置为undefined。当globalFilterFn指定了字符串但该函数未注册时开发环境下会输出globalFilterFn xxx is not registered的警告便于排查拼写或注册遗漏。组合建议与调试提示先注册、后引用globalFilterFn: includesString这类字符串引用依赖filterFns槽位中已注册同名函数直接传函数则无需注册且天然利于 tree-shaking。与分页/排序协作客户端过滤在行模型管线中位于预过滤行模型之后过滤结果再交给排序与分页服务端过滤则要自行处理globalFilter变化时的数据请求与分页重置见 客户端 vs 服务端指南。响应式接入在 Angular 中凡是读取table.atoms.globalFilter.get()的模板表达式、computed或effect都会随过滤值自动更新配合ChangeDetectionStrategy.OnPush与FlexRender指令即可获得高性能的按需渲染。对照示例完整可运行代码可参考 列过滤示例 与 模糊搜索示例Angular 版本均位于examples/angular目录前者覆盖基础列过滤后者展示了模糊全局过滤 排序 分页的完整组合。【免费下载链接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table项目地址: https://gitcode.com/gh_mirrors/ta/table创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表