完整实战指南)
TanStack Table React 模糊过滤Fuzzy 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模糊过滤Fuzzy Filtering是一种基于近似匹配的过滤技术允许用户在搜索数据时不必输入精确值即可命中相似结果是现代数据表格中搜索体验的关键一环。本指南基于 TanStack Table React 官方文档深入讲解如何利用tanstack/match-sorter-utils库为表格定义自定义模糊过滤函数、将其接入全局过滤与列过滤并结合匹配排名信息实现按相关度排序的完整链路。读完本文你将掌握从功能装配tableFeatures、类型安全filterMeta插槽到 UI 接线与源码原理的整套实战方案可直接复刻到自己的数据表格项目中。前置准备与示例工程在动手实现之前建议先查看仓库中已完成的官方示例直观理解模糊过滤在真实表格中的表现Fuzzy Search React 示例完整的可运行工程包含 5000 行数据的表格、全局搜索框、每列过滤输入框、分页与排名排序效果。Global FilteringReact指南模糊过滤最常见的落地场景——全局过滤两个文档配合阅读效果更佳。示例工程的入口源码位于 examples/react/filters-fuzzy/src/main.tsx其中通过columnHelper定义了四列id精确匹配equalsString、firstName大小写敏感包含includesStringSensitive、lastName大小写不敏感包含includesString以及核心的fullName模糊过滤 模糊排序。同时它注册了rowPaginationFeature与分页行模型演示模糊过滤与分页共存。安装依赖使用模糊过滤前需要安装两个包npm install tanstack/react-table tanstack/match-sorter-utils[!NOTE]tanstack/match-sorter-utils是 Kent C. Dodds 的 match-sorter 库的 TanStack 分支专为适配 TanStack Table 逐行过滤row by row filtering的工作方式而 fork。它提供rankItem与compareItems两个底层工具先用rankItem给单个条目打分再用返回的RankingInfo中的passed字段决定是否过滤、用rank字段决定排序。这正是它区别于一次完成过滤排序的传统 match-sorter API 的关键设计——在源码头部注释中写明了这一增量式incrementally applied使用方式见 packages/match-sorter-utils/src/index.ts。功能装配在 tableFeatures 中启用模糊过滤TanStack Table v9 采用功能组合feature composition的架构。添加模糊过滤相关功能后对应的 API 才会启用。若使用客户端模糊过滤与排序必须在对应功能之后挂载filteredRowModel和sortedRowModel因为行模型插槽是经过类型检查type-checked的。import { useTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, rowSortingFeature, createFilteredRowModel, createSortedRowModel, metaHelper, } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowSortingFeature, filteredRowModel: createFilteredRowModel(), // if using client-side filtering // manualFiltering: true, // if using manual server-side filtering sortedRowModel: createSortedRowModel(), // if using client-side sorting // manualSorting: true, // if using manual server-side sorting filterFns: { fuzzy: fuzzyFilter }, sortFns: { fuzzy: fuzzySort }, filterMeta: metaHelperFuzzyFilterMeta(), }) const table useTable({ features, columns, data, })各配置项含义如下配置项作用备注columnFilteringFeature启用列过滤全局过滤依赖列过滤必须先注册参考 global-filtering.mdglobalFilteringFeature启用全局过滤依赖columnFilteringFeaturerowSortingFeature启用排序为按模糊排名排序提供能力filteredRowModel客户端过滤行模型使用客户端过滤时必须提供否则行模型插槽类型检查不通过manualFiltering服务端手动过滤开关数据已由服务端过滤时置为true跳过内置过滤逻辑sortedRowModel客户端排序行模型使用客户端排序时必须提供manualSorting服务端手动排序开关数据已由服务端排序时置为truefilterFns过滤函数注册表按字符串名引用过滤函数sortFns排序函数注册表按字符串名引用排序函数filterMeta过滤元数据类型插槽用metaHelperFuzzyFilterMeta()声明类型见下文[!NOTE] 上面的filterFns与sortFns注册表只列出了本指南用到的自定义fuzzy函数。虽然展开全部内置注册表filterFns: { ...filterFns, fuzzy: fuzzyFilter }仍然可用但会把每个内置函数都打进你的 bundle。最佳实践是只注册实际用到的函数或者完全不注册、直接把函数传给列的filterFn与sortFn选项。定义自定义模糊过滤函数模糊过滤的核心是一个自定义过滤函数它接收行row、列 IDcolumnId与过滤值value返回布尔值决定该行是否保留。同时它通过addMeta回调把排名信息附加到行上供后续排序使用。定义过滤元数据类型首先定义过滤元数据的形状以及携带它的 features 类型import { rankItem } from tanstack/match-sorter-utils import type { RankingInfo } from tanstack/match-sorter-utils import type { FilterFn, RowData, TableFeatures } from tanstack/react-table interface FuzzyFilterMeta { itemRank?: RankingInfo } // A features type that carries the filterMeta shape type FuzzyFeatures TableFeatures { filterMeta: FuzzyFilterMeta }实现模糊过滤函数const fuzzyFilter: FilterFnFuzzyFeatures, RowData ( row, columnId, value, addMeta, ) { // Rank the item const itemRank rankItem(row.getValue(columnId), value) // Store the itemRank info addMeta?.({ itemRank, }) // Return if the item should be filtered in/out return itemRank.passed }函数逻辑分三步打分调用rankItem(row.getValue(columnId), value)将当前单元格的值与搜索词比较得到RankingInfo。从tanstack/match-sorter-utils的源码看rankItem内部会依次尝试大小写敏感相等、相等、开头匹配、单词开头匹配、包含、首字母缩略词等策略最终给出 0NO_MATCH到 7CASE_SENSITIVE_EQUAL之间的排名分数见 packages/match-sorter-utils/src/index.ts。存元数据addMeta?.(...)是可选回调因此用可选链调用调用后排名信息会写入该行对应列的columnFiltersMeta[columnId]中。决定去留返回itemRank.passed。passed是rank threshold的结果默认阈值是rankings.MATCHES值为 1即只要存在松散匹配就算通过见 packages/match-sorter-utils/src/index.ts。在 tableFeatures 中注册要以字符串名fuzzy引用该过滤函数并让存储的过滤元数据获得正确类型需要在tableFeatures调用中通过filterFns与filterMeta插槽同时注册import { tableFeatures, metaHelper } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowSortingFeature, filteredRowModel: createFilteredRowModel(), sortedRowModel: createSortedRowModel(), filterFns: { fuzzy: fuzzyFilter }, sortFns: { fuzzy: fuzzySort }, filterMeta: metaHelperFuzzyFilterMeta(), })这里不需要任何declare module全局模块增强。从源码实现看filterMeta插槽是一个类型优先type-only的槽位当 features 对象通过filterMeta声明了元数据类型时ExtractFilterMeta类型工具会让该类型生效否则回退到全局声明合并的FilterMeta接口见 packages/table-core/src/features/column-filtering/columnFilteringFeature.types.ts。filterFns与filterMeta插槽的作用域都限定在该 features 对象内只会影响用该 features 创建的表格不会污染全局类型环境。模糊过滤 全局过滤模糊过滤最典型的应用场景是全局过滤Global Filtering——一个搜索词同时匹配所有参与全局过滤的列。做法是在tableFeatures的filterFns插槽注册模糊过滤函数再在表格的globalFilterFn选项中按名称引用它import { useTable, tableFeatures, columnFilteringFeature, globalFilteringFeature, rowSortingFeature, createFilteredRowModel, createSortedRowModel, metaHelper, } from tanstack/react-table const features tableFeatures({ columnFilteringFeature, globalFilteringFeature, rowSortingFeature, filteredRowModel: createFilteredRowModel(), sortedRowModel: createSortedRowModel(), // needed if you want sorting with fuzzy rank filterFns: { fuzzy: fuzzyFilter }, sortFns: { fuzzy: fuzzySort }, filterMeta: metaHelperFuzzyFilterMeta(), }) const table useTable({ features, columns, data, globalFilterFn: fuzzy, })注意globalFilteringFeature依赖columnFilteringFeature两者的注册顺序不能颠倒。TanStack Table 不会自动渲染全局过滤输入框需要自己添加 UI通过table.state.globalFilter响应式读取当前值用table.setGlobalFilter更新。官方示例使用了一个基于useDebouncedCallback来自tanstack/react-pacer的DebouncedInput组件默认 500ms 防抖避免每次按键都触发对 5000 行数据的过滤计算见 examples/react/filters-fuzzy/src/main.tsx。关于全局过滤的更多细节globalFilter状态管理、外部 atom 接管、enableGlobalFilter禁用开关等请参见 全局过滤指南。模糊过滤 列过滤模糊过滤同样可以作用于单列。将模糊过滤函数注册到tableFeatures的filterFns插槽见上文装配一节后在列定义中通过filterFn选项按名称指定即可const column [ { accessorFn: (row) ${row.firstName} ${row.lastName}, id: fullName, header: Full Name, cell: (info) info.getValue(), filterFn: fuzzy, // using our custom fuzzy filter function }, // other columns... ]这个例子把模糊过滤应用在拼接firstName与lastName生成的fullName列上——用户只需输入名或姓的一部分即可模糊命中。在官方示例中这一列同时搭配了sortFn: fuzzy形成过滤 按相关度排序的完整体验见 examples/react/filters-fuzzy/src/main.tsx。结合模糊排名排序使用列过滤的模糊过滤时你可能还希望基于排名信息对结果排序——让最接近搜索词的行排在最前面。定义一个自定义排序函数即可import { compareItems } from tanstack/match-sorter-utils import { sortFn_alphanumeric } from tanstack/react-table import type { SortFn } from tanstack/react-table const fuzzySort: SortFnFuzzyFeatures, Person (rowA, rowB, columnId) { let dir 0 // Only sort by rank if the column has ranking information if (rowA.columnFiltersMeta[columnId]) { dir compareItems( rowA.columnFiltersMeta[columnId].itemRank!, rowB.columnFiltersMeta[columnId].itemRank!, ) } // Provide an alphanumeric fallback for when the item ranks are equal return dir 0 ? sortFn_alphanumeric(rowA, rowB, columnId) : dir }该函数的核心逻辑读取排名元数据rowA.columnFiltersMeta[columnId]中保存了前面fuzzyFilter通过addMeta写入的itemRank。之所以能安全读取是因为filterMeta: metaHelperFuzzyFilterMeta()已让columnFiltersMeta的类型带上itemRank字段。比较排名compareItems直接比较两个RankingInfo的rank字段——rank高者排前相等返回 0见 packages/match-sorter-utils/src/index.ts。字母序兜底当两者排名相等或该列没有排名信息时回退到内置的sortFn_alphanumeric字母序排序保证排序结果稳定可预期。注册排序函数并在列上引用将fuzzySort注册到tableFeatures的sortFns插槽见上文装配一节然后在列定义中按名称引用{ accessorFn: row ${row.firstName} ${row.lastName}, id: fullName, header: Full Name, cell: info info.getValue(), filterFn: fuzzy, // using our custom fuzzy filter function (registered in features) sortFn: fuzzy, // using our custom fuzzy sort function (registered in features) }也可以跳过注册步骤把fuzzySort直接作为函数传给列的sortFn选项——两种方式等价选择哪种取决于你是否需要在多处按名称引用同一个函数。源码原理排名体系与类型插槽为了让方案落地更稳这里补充两个来自仓库源码的关键原理。排名分数体系tanstack/match-sorter-utils定义了一套从强到弱的匹配等级见 packages/match-sorter-utils/src/index.ts排名常量值含义CASE_SENSITIVE_EQUAL7大小写敏感完全相等EQUAL6忽略大小写完全相等STARTS_WITH5以搜索词开头WORD_STARTS_WITH4单词以搜索词开头CONTAINS3包含搜索词ACRONYM2首字母缩略词匹配MATCHES1字符有序松散匹配默认阈值NO_MATCH0不匹配rankItem默认阈值为MATCHES1因此只要达到最松散的字符有序匹配即视为passed。比较两个条目时compareItems按分数高低直接判序。这套设计让过滤与排序共享同一份打分结果过滤看passed排序看rank。filterMeta 类型插槽如何工作columnFiltersMeta是行对象上按列 ID 索引的元数据容器见 packages/table-core/src/features/column-filtering/columnFilteringFeature.types.ts。metaHelperFuzzyFilterMeta()的本质是在 features 对象上声明一个类型优先的filterMeta插槽ExtractFilterMeta类型工具会优先采用该插槽类型、否则回退到全局合并的FilterMeta。这意味着自定义过滤函数在addMeta写入的数据能在排序函数里被类型安全地读取columnFiltersMeta[columnId].itemRank已知类型不需要declare module全局增强不同表格可以携带不同的元数据类型而互不冲突所有类型约束都限定在tableFeatures(...)产生的 features 对象作用域内。完整示例与验证仓库中的 filters-fuzzy 示例 是上述全部概念的可运行实现数据层makeData.ts生成 5000 行模拟数据并提供重新生成与百万行压力测试按钮交互层全局模糊搜索框防抖 500ms 每列独立过滤输入框 分页控件行为细节useEffect中当fullName列被过滤时自动把排序切换到fullName列从而立即体现按模糊排名排序的效果见 examples/react/filters-fuzzy/src/main.tsx测试保障配套 Playwright 冒烟测试覆盖表格正常渲染无报错与重新生成数据后首行内容变化两个场景见 examples/react/filters-fuzzy/tests/e2e/smoke.spec.ts。运行该示例的方式与仓库其他示例一致在examples/react/filters-fuzzy目录下安装依赖并启动 Vite 开发服务器即可在浏览器中体验完整的模糊搜索交互。小结本文完整覆盖了 TanStack Table React 模糊过滤的落地路径安装tanstack/match-sorter-utils理解rankItem打分 compareItems排序的增量式设计在tableFeatures中装配columnFilteringFeature、globalFilteringFeature、rowSortingFeature及对应的行模型定义携带RankingInfo的自定义fuzzyFilter通过addMeta写入排名信息用filterFns与filterMeta插槽完成注册与类型绑定分别接入全局过滤globalFilterFn: fuzzy与列过滤列定义filterFn: fuzzy定义fuzzySort排序函数用compareItems比较排名、以sortFn_alphanumeric兜底实现最相关结果排最前借助filterMeta类型插槽机制无需全局类型增强即可获得端到端类型安全。这套方案兼顾了模糊搜索的体验与工程上的类型严谨性可以直接复用到任何基于 TanStack Table React 构建的数据表格与数据网格中。【免费下载链接】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),仅供参考