前端UI组件【免费下载链接】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点击查看免费下载分面Faceting是 TanStack Table 中用于构建高级筛选界面的核心能力它不直接筛选数据而是为筛选项生成“还有哪些可选值、每个值出现多少次、数值范围是多少”等元数据从而驱动复选框、下拉菜单、自动补全与范围滑块等筛选控件。本文以 Table_ColumnFaceting 接口文档 为骨架结合table-core的源码实现与测试用例完整讲解该接口的三个全局分面 APIgetGlobalFacetedMinMaxValues、getGlobalFacetedRowModel、getGlobalFacetedUniqueValues的类型签名、返回值语义、底层调用链与实战用法。读完后你将能够在 React、Vue、Solid、Svelte 等框架中准确使用分面能力并能基于源码理解其缓存策略与自定义扩展点。接口概览Table_ColumnFaceting 在分面 API 体系中的位置Table_ColumnFaceting是一个挂在Table 实例上的接口区别于挂在单个 column 上的Column_ColumnFaceting专门承载**全局筛选global filter**场景下的分面元数据。从 columnFacetingFeature.types.ts 可以看到该接口定义在packages/table-core/src/features/column-faceting/columnFacetingFeature.types.ts中与同一文件内的另外两个分面接口构成完整的分面 API 体系接口挂载对象职责Column_ColumnFaceting单个列提供getFacetedRowModel()、getFacetedMinMaxValues()、getFacetedUniqueValues()描述某一列的分面结果Table_RowModels_Faceted表格行模型维度与Column_ColumnFaceting相同的三个方法签名强调这些能力依赖features选项中注册的行模型工厂Table_ColumnFaceting表格全局筛选维度提供getGlobalFacetedRowModel()、getGlobalFacetedMinMaxValues()、getGlobalFacetedUniqueValues()描述全局筛选的分面结果三个接口全部是泛型接口类型参数与 TanStack Table 全库一致TFeatures extends TableFeatures表格启用的功能特性集合定义在 TableFeaturesTData extends RowData数据行的类型约束定义在 RowData相对原文档位置为docs/reference/index/type-aliases/RowData.md。其中in out修饰符表示类型参数同时具备协变covariant与逆变contravariant能力允许接口在更广泛的泛型上下文中安全复用。从源码结构可以推断三种接口分别服务于“列筛选 UI”“行模型管道”“全局搜索框”三类使用场景但底层都复用同一套createFaceted*工厂与行模型槽位这正是 TanStack Table 分面 API 高度统一的原因。getGlobalFacetedRowModel()全局分面的行模型来源类型签名与返回值getGlobalFacetedRowModel: () RowModelTFeatures, TData;作用计算用于推导全局分面值的行模型。返回值类型为 RowModel即包含rows深层行与flatRows扁平行的标准行模型对象。源码级实现缓存与工厂回退getGlobalFacetedRowModel的实际实现位于 columnFacetingFeature.utils.ts 的table_getGlobalFacetedRowModelexport function table_getGlobalFacetedRowModel TFeatures extends TableFeatures, TData extends RowData, (table: Table_InternalTFeatures, TData): RowModelTFeatures, TData { if (!table._rowModels.globalFacetedRowModel) { table._rowModels.globalFacetedRowModel table.options.features.facetedRowModel?.(table, __global__) ?? (() table.getPreFilteredRowModel()) } const facetedRowModelFn table._rowModels.globalFacetedRowModel return facetedRowModelFn() }关键点有三内部列 ID__global__全局上下文以保留字__global__作为列 ID 请求行模型工厂。自定义工厂可以通过判断columnId __global__分支处理全局与逐列的不同逻辑后文自定义章节详述。工厂结果按表格缓存工厂函数本身facetedRowModel只在第一次读取时通过table._rowModels.globalFacetedRowModel缓存一次但工厂返回的函数在每次调用时都会重新执行以保证读到的数据是最新的。工厂缺失回退若未在features中注册facetedRowModel工厂则回退到table.getPreFilteredRowModel()预筛选行模型此时全局分面值不会响应其他列的筛选。与列级分面行模型的关系全局分面行模型与列级分面行模型在语义上完全对称列级getFacetedRowModel()应用除本列之外的其他所有筛选columnFacetingFeature.utils.ts 中通过id ! columnId排除本列全局分面行模型则应用所有有效列筛选、排除全局筛选本身createFacetedRowModel.ts 中if (hasGlobalFilter columnId ! __global__)的逻辑。这种对称性保证了分面 UI 的“自排除”行为编辑当前分面时其他可选值仍然保留。实战用法// 获取全局分面行模型常用于自定义全局分面计算 const globalFacetedRows table.getGlobalFacetedRowModel().flatRows // 在 React 响应式组件中配合 table.Subscribe 订阅全局筛选状态 table.Subscribe selector{(state) state.globalFilter} {() { const rows table.getGlobalFacetedRowModel().flatRows /* 基于行模型做自定义统计 */ }} /table.SubscribegetGlobalFacetedUniqueValues()全局唯一值与其出现次数类型签名与返回值getGlobalFacetedUniqueValues: () Mapany, number;作用返回全局筛选上下文中各唯一值及其出现次数。键为任意类型的唯一值any值为出现次数number。该 API 是构建全局搜索框自动补全建议的核心数据源。源码级实现跨列聚合与 undefined 保留底层实现在 columnFacetingFeature.utils.ts 的table_getGlobalFacetedUniqueValues同样按表格缓存工厂、缺失时回退到“稳定空 Map”每次返回同一个Map实例保证引用稳定性见同一文件的createStableEmptyMapFnL109-L112。真正的统计逻辑在 createFacetedUniqueValues.ts 的_createFacetedUniqueValuesconst columnIds columnId __global__ ? table .getAllLeafColumns() .filter((column) column_getCanGlobalFilter(column)) .map((column) column.id) : [columnId]全局模式跨列聚合与列级分面只统计单列不同全局分面会遍历所有叶子列并只纳入允许参与全局筛选的列通过column_getCanGlobalFilter判断即列必须设置了enableGlobalFilter且有可用的全局筛选函数。逐值计数对每一行、每一列调用row.getUniqueValues(columnId)获取值数组逐值累加计数。某行对某列返回undefined如 display 列无 accessor时直接跳过。undefined 不被丢弃测试用例 columnFacetingFeature.test.ts 明确验证了undefined值会作为键保留在 Map 中——这是构建“未分类”筛选项时必须注意的行为。实战用法全局搜索自动补全const suggestions Array.from(table.getGlobalFacetedUniqueValues().entries()) .sort(([valueA], [valueB]) String(valueA).localeCompare(String(valueB))) .slice(0, 5_000) // 渲染为下拉/自动补全选项每项显示 (count) return ( select {suggestions.map(([value, count]) ( option key{String(value)} value{String(value)} {String(value)} ({count}) /option ))} /select )计数语义注意事项对于标量列每行通常贡献一个值因此出现次数即行数。但若列通过getUniqueValues选项返回多个值计数就是“出现次数”总和可能超过行数。若希望每个计数代表行数应保证getUniqueValues对每行最多返回每个值一次。getGlobalFacetedMinMaxValues()全局数值范围类型签名与返回值getGlobalFacetedMinMaxValues: () [number, number] | undefined;作用返回全局筛选上下文中的数值最小值和最大值返回[number, number]二元组当不存在任何可用的数值时返回undefined。该 API 专为数字输入框与范围滑块设计。源码级实现跨列求极值实现在 columnFacetingFeature.utils.ts 的table_getGlobalFacetedMinMaxValues同样缓存工厂、缺失时回退undefined。极值计算在 createFacetedMinMaxValues.tslet facetedMinValue Number.POSITIVE_INFINITY let facetedMaxValue Number.NEGATIVE_INFINITY let foundAny false for (let i 0; i flatRows.length; i) { for (let c 0; c columnIds.length; c) { const value Number(flatRows[i]!.getValue(columnIds[c]!)) if (Number.isNaN(value)) continue foundAny true if (value facetedMinValue) facetedMinValue value if (value facetedMaxValue) facetedMaxValue value } } if (!foundAny) return undefined return [facetedMinValue, facetedMaxValue]实现要点跨列扫描所有可参与全局筛选的叶子列通过Number()强转后比较NaN被跳过。空行或全NaN时返回undefined这是调用方必须做空值兜底的原因。与列级getFacetedMinMaxValues()相同范围描述的是应用其他筛选后仍可选的数值区间而非全表范围。实战用法范围滑块const [min, max] table.getGlobalFacetedMinMaxValues() ?? [0, 1] return ( input typerange min{min} max{max} value{currentValue} onChange{(event) table.setGlobalFilter(Number(event.target.value))} / )三个 API 的依赖与前置条件工厂注册与功能启用三个全局分面 API 都依赖在features中注册的行模型工厂且与列级分面共享同一套工厂。完整的前置条件如下前置条件说明相关源码columnFacetingFeature启用分面特性将三个 API 挂载到 Table 实例上columnFacetingFeature.ts 中constructTableAPIs注册table_getGlobalFacetedRowModel等三个方法facetedRowModel: createFacetedRowModel()客户端分面行模型工厂驱动getGlobalFacetedRowModel()缺失时回退预筛选行模型createFacetedRowModel.tsfacetedUniqueValues: createFacetedUniqueValues()唯一值统计工厂驱动getGlobalFacetedUniqueValues()缺失时返回稳定空 MapcreateFacetedUniqueValues.tsfacetedMinMaxValues: createFacetedMinMaxValues()数值极值工厂驱动getGlobalFacetedMinMaxValues()缺失时返回undefinedcreateFacetedMinMaxValues.tsglobalFilteringFeature使用全局筛选时需启用否则全局筛选在行筛选管道中不会生效Global Faceting 一节标准安装方式以 React 为例Vue/Solid/Svelte 等框架的包名与 API 对应替换import { useTable, tableFeatures, columnFacetingFeature, globalFilteringFeature, createFacetedRowModel, createFacetedUniqueValues, createFacetedMinMaxValues, } from tanstack/react-table const features tableFeatures({ columnFacetingFeature, globalFilteringFeature, facetedRowModel: createFacetedRowModel(), facetedUniqueValues: createFacetedUniqueValues(), facetedMinMaxValues: createFacetedMinMaxValues(), }) const table useTable({ features, columns, data, })注意注册工厂后行模型槽位会进行类型检查row model slots are type-checked因此工厂注册的顺序与类型匹配需要符合框架约定。若使用服务端筛选manualFiltering: true则无需注册客户端facetedRowModel但自定义服务端分面工厂依然可用见下节。缓存与记忆化策略理解getGlobalFaceted*的重复调用成本columnFacetingFeature的设计决策值得特别注意。在 columnFacetingFeature.ts 的注释中明确写道这些 API 有意不在这一层做记忆化memoized内置的createFaceted*工厂内部自行记忆化与所有内置行模型一致如果在这里再套一层记忆化会冻结那些数据独立于分面行模型变化的自定义工厂。自定义工厂自己负责记忆化。因此内存化分层如下getGlobalFaceted*API 本身只缓存“工厂函数引用”每次调用都会执行工厂返回的函数保证读到最新数据columnFacetingFeature.utils.ts 的“先取缓存工厂、再立即调用”模式内置createFaceted*工厂通过tableMemo记忆化依赖输入行模型与相关筛选状态列筛选、全局筛选变化才重算createFacetedUniqueValues.ts 的memoDeps返回flatRows、columnFilters、globalFilter等工厂按列缓存table._rowModels.facetedUniqueValues等缓存对象按column.id含__global__存工厂测试用例 columnFacetingFeature.test.ts 验证了工厂对每个列 ID 只解析一次、对__global__单独解析一次。测试还验证了未注册工厂时的回退行为仅筛选本列时getFacetedRowModel()直接复用预筛选行模型L68-L75其他列的筛选仍然生效L77-L87。自定义服务端分面用__global__分支对接远程数据当筛选在服务端执行时浏览器中的行数据不足以计算完整的分面值。此时可提供自定义facetedUniqueValues与facetedMinMaxValues工厂三个getGlobalFaceted*API 会直接返回服务端提供的结果const features tableFeatures({ columnFacetingFeature, // 返回的函数每次读取时都会执行因此通过 options.meta 读取实时数据 facetedUniqueValues: (table, columnId) () { if (columnId __global__) { return new Map(table.options.meta?.serverFacets?.globalUniqueValues ?? []) } return new Map(table.options.meta?.serverFacets?.uniqueValues[columnId] ?? []) }, facetedMinMaxValues: (table, columnId) () { return table.options.meta?.serverFacets?.minMaxValues[columnId] }, }) const table useTable({ features, columns, data, meta: { serverFacets: facetingQuery.data }, })关键约定__global__分支自定义工厂通过内部保留 ID__global__区分全局与逐列请求见 columnFacetingFeature.utils.ts 的注释与实现排除自身筛选为匹配内置列分面行为服务端按列查询时应应用其他有效筛选、排除该列自身的筛选保证编辑当前分面时其他选项仍可见全局查询则应应用列筛选、排除全局筛选本身工厂内记忆化表格不会缓存工厂返回函数的计算结果若计算昂贵应在工厂内部自行记忆化。全局分面在实践中的完整工作流综合以上内容一个基于全局分面的“搜索 自动补全 范围筛选”工作流可以这样组织function GlobalSearch() { return ( table.Subscribe selector{(state) state.globalFilter} {() { // 1. 行模型驱动自定义统计或派生数据 const globalRows table.getGlobalFacetedRowModel().flatRows // 2. 唯一值自动补全建议每项附出现次数 const suggestions Array.from( table.getGlobalFacetedUniqueValues().entries(), ) .sort(([a], [b]) String(a).localeCompare(String(b))) .slice(0, 5_000) // 3. 数值范围范围滑块/数字输入上下界 const [min, max] table.getGlobalFacetedMinMaxValues() ?? [0, 1] return ( div input typesearch placeholder搜索… listsuggestions onChange{(e) table.setGlobalFilter(e.target.value)} / datalist idsuggestions {suggestions.map(([value]) ( option key{String(value)} value{String(value)} / ))} /datalist input typerange min{min} max{max} value{Number(table.getState().globalFilter) || min} onChange{(e) table.setGlobalFilter(Number(e.target.value))} / p匹配行数{globalRows.length}/p /div ) }} /table.Subscribe ) }注意三个数据源的联动语义唯一值与数值范围都基于getGlobalFacetedRowModel()的行集合而该集合排除了全局筛选自身、但应用了所有列筛选——因此当其他列的分面筛选项变化时全局建议与范围会自动收窄。性能建议与注意事项限制渲染量高基数列的唯一值 Map 可能很大应只渲染前若干条或允许用户先搜索再展示内置示例中常取前5_000条就近订阅避免在无关组件中反复排序/转换大的分面 Map应把分面选项的推导与渲染放在订阅了相关筛选状态的组件内table.Subscribe使订阅局部化分桶降基数日期、文件大小、价格等连续值可借助列的getUniqueValues返回分桶键同时保持原始 accessor 值用于渲染可参考 分桶分面示例其他框架在examples/framework/filters-faceted-bucketed下有对应版本大表走服务端当完整数据不在浏览器中时优先将分面计算移到服务端并按上文“自定义服务端分面”的方式注入。更完整的端到端实现可参考各框架的 Faceted Filters 示例examples/framework/filters-faceted以及框架分面指南 React、Vue、Svelte、Solid 等列级分面接口可对照 Column_ColumnFaceting 与 Table_RowModels_Faceted 文档阅读。赞分享前端UI组件【免费下载链接】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点击查看免费下载相关推荐深入解析 TanStack Table 的 CachedRowModel_Faceted 接口列刻面Faceting行模型缓存的类型契约与底层实现深入解析 TanStack Table 的 CachedRowModel_Faceted 接口列刻面Faceting行模型缓存的类型契约与底层实现 导读前端UI组件TanStack Table Octane 列分面Column Faceting实战指南从行模型工厂到过滤界面TanStack Table Octane 列分面Column Faceting实战指南从行模型工厂到过滤界面 Faceting分面是构建筛选式数据表前端UI组件TanStack Angular Table 列分面Column Faceting指南构建可筛选的统计型过滤界面TanStack Angular Table 列分面Column Faceting指南构建可筛选的统计型过滤界面 导读 本文基于 TanStack Tab前端UI组件创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考