戰(zhàn))
前端UI組件【免費(fèi)下載鏈接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table項(xiàng)目地址https://gitcode.com/gh_mirrors/ta/table點(diǎn)擊查看免費(fèi)下載TanStack Table即本倉(cāng)庫(kù) ta/table 所鏡像的 headless 表格框架中列寬Column Sizing是每個(gè)表格在渲染時(shí)都必須處理的基礎(chǔ)能力。ColumnDef_ColumnSizing是定義在 packages/table-core/src/features/column-sizing/columnSizingFeature.types.ts 中的列定義ColumnDef混入接口它只包含三個(gè)可選屬性size、minSize、maxSize卻完整地決定了每列初始寬度、可收縮下限與可拉伸上限。讀完本文你將理解這三個(gè)參數(shù)的優(yōu)先級(jí)、鉗制clamp算法、與columnSizing狀態(tài)及columnResizing交互的關(guān)系并能基于源碼寫出可復(fù)制的列寬配置。一、接口總覽三個(gè)可選數(shù)值屬性ColumnDef_ColumnSizing是列定義接口的“切片”之一當(dāng)表實(shí)例注冊(cè)了columnSizingFeature后每個(gè)ColumnDef都會(huì)獲得這三個(gè)可選屬性。完整定義如下見 columnSizingFeature.types.tsexport interface ColumnDef_ColumnSizing { /** * Upper bound used when resolving this columns size. */ maxSize?: number /** * Lower bound used when resolving this columns size. */ minSize?: number /** * Initial size used before column sizing state overrides it. */ size?: number }三個(gè)屬性的語(yǔ)義非常明確屬性類型默認(rèn)值含義sizenumber150列的初始尺寸像素在columnSizing狀態(tài)覆蓋它之前生效minSizenumber20解析該列尺寸時(shí)使用的下界最小寬度maxSizenumberNumber.MAX_SAFE_INTEGER解析該列尺寸時(shí)使用的上界最大寬度值得注意的是這三個(gè)屬性的默認(rèn)值并非寫在接口上而是由 feature 的內(nèi)置默認(rèn)列定義提供。在 columnSizingFeature.utils.ts 中export function getDefaultColumnSizingColumnDef() { return { size: 150, minSize: 20, maxSize: Number.MAX_SAFE_INTEGER, } }也就是說(shuō)不配置任何列寬時(shí)TanStack Table 的每一列默認(rèn)寬 150px、最小可縮到 20px、最大理論上不限。該默認(rèn)值被columnSizingFeature的getDefaultColumnDef鉤子注入到每個(gè)列定義上見 columnSizingFeature.ts。二、size初始尺寸與狀態(tài)覆蓋機(jī)制size的官方注釋是 “Initial size used before column sizing state overrides it”在 column sizing 狀態(tài)覆蓋它之前使用的初始尺寸。這揭示了一條重要的解析順序state.columnSizing[column.id]的優(yōu)先級(jí)高于columnDef.size。也就是說(shuō)size并不是“最終渲染寬度”而是“初始建議寬度”。一旦用戶通過(guò)拖拽列頭邊緣調(diào)整了列寬或者程序通過(guò)table.setColumnSizing()/onColumnSizingChange寫入了該列的尺寸state.columnSizing中記錄的數(shù)值就會(huì)覆蓋size。從源碼看columnSizingFeature的初始狀態(tài)是一個(gè)空對(duì)象getDefaultColumnSizingState()返回makeObjectMap()所以默認(rèn)情況下每列都回退到columnDef.size見 columnSizingFeature.utils.ts。對(duì)應(yīng)的單元測(cè)試也驗(yàn)證了這一點(diǎn)未配置size時(shí)column_getSize()返回內(nèi)置默認(rèn)值150配置size: 200時(shí)葉子表頭header.getSize()返回200當(dāng)state.columnSizing中記錄{ a: 250 }時(shí)即使columnDef.size是100最終解析結(jié)果也是250見 columnSizingFeature.utils.test.ts。分組表頭如何繼承 sizesize不僅作用于葉子列。對(duì)于分組列擁有子列的父列其表頭尺寸是所有后代葉子列尺寸之和。測(cè)試用例證明外層分組outer包含innerinner包含a(100px)與b(200px)此時(shí)inner.getSize()與outer.getSize()均為300一旦通過(guò)table.setColumnSizing({ a: 400 })修改葉子列寬兩級(jí)分組表頭會(huì)同步重算為600見 columnSizingFeature.utils.test.ts。三、minSize最小寬度的下界約束minSize定義了列在解析尺寸時(shí)允許的最小值。它有兩層作用限制拖拽縮小的下限當(dāng)用戶拖動(dòng)列頭 resize handle 時(shí)即使拖拽量再大最終解析出的尺寸也不會(huì)低于minSize鉗制非法狀態(tài)值如果columnSizing狀態(tài)中被人為寫入了一個(gè)小于minSize的數(shù)值解析結(jié)果同樣會(huì)被抬升回minSize。源碼中的鉗制邏輯位于column_getSize()見 columnSizingFeature.utils.tsreturn Math.min( Math.max( column.columnDef.minSize ?? defaultSizes.minSize, columnSize ?? column.columnDef.size ?? defaultSizes.size, ), column.columnDef.maxSize ?? defaultSizes.maxSize, )解析順序可以概括為三步候選寬度 state.columnSizing[column.id]若存在→ 否則columnDef.size→ 否則內(nèi)置默認(rèn)150先用Math.max與minSize比較低于下限則抬升下限 columnDef.minSize或內(nèi)置默認(rèn)20再用Math.min與maxSize比較超過(guò)上限則壓低上限 columnDef.maxSize或內(nèi)置默認(rèn)Number.MAX_SAFE_INTEGER。測(cè)試用例should clamp to minSize驗(yàn)證列定義minSize: 50、狀態(tài)寫入{ a: 5 }最終column_getSize()返回50見 columnSizingFeature.utils.test.ts。四、maxSize最大寬度的上界約束maxSize與minSize對(duì)稱定義了列寬解析的上限。默認(rèn)值為Number.MAX_SAFE_INTEGER意味著默認(rèn)情況下列寬沒(méi)有實(shí)際的上限只有顯式配置maxSize時(shí)才會(huì)生效。它的典型應(yīng)用場(chǎng)景包括內(nèi)容很長(zhǎng)的列如“描述”“備注”限制其最大寬度以避免過(guò)度擠壓其他列固定寬度徽標(biāo)列、操作按鈕列防止其在容器變寬時(shí)被拉伸與minSize組合形成“固定區(qū)間”讓列只能在區(qū)間內(nèi)伸縮。測(cè)試用例should clamp to maxSize驗(yàn)證列定義size: 500, maxSize: 300且無(wú)狀態(tài)覆蓋時(shí)解析結(jié)果被鉗制為300見 columnSizingFeature.utils.test.ts。需要特別注意的是minSize與maxSize同時(shí)存在時(shí)鉗制順序先max(minSize, 候選值)再min(maxSize, …)。如果配置的minSize maxSize最終結(jié)果會(huì)落到maxSize上因此配置時(shí)應(yīng)保證minSize size maxSize。五、三個(gè)屬性如何協(xié)作完整解析鏈路把上面的內(nèi)容串起來(lái)一列“最終渲染寬度”的解析鏈路如下候選值 state.columnSizing[column.id] ?? columnDef.size ?? 150內(nèi)置默認(rèn) 最終值 clamp(候選值, minSize 或 20, maxSize 或 Number.MAX_SAFE_INTEGER)這條鏈路體現(xiàn)在column_getSize()中而其上層 API 鏈為column.getSize()—— 解析該列當(dāng)前寬度葉子列使用上述 clamp 結(jié)果分組列遞歸求和子列header.getSize()—— 表頭的渲染寬度葉子表頭取列寬分組表頭遞歸累加table.getTotalSize()/getStartTotalSize()/getCenterTotalSize()/getEndTotalSize()—— 整表及固定區(qū)域的合計(jì)寬度。這些 API 的 memo 依賴被精心設(shè)計(jì)葉子列的getSize只依賴columnSizing狀態(tài)中該列自己的條目而分組表頭與getStart/getAfter偏移量則依賴整個(gè)columnSizing狀態(tài)以保證子列尺寸變化時(shí)父級(jí)與偏移量能正確失效重算見 columnSizingFeature.ts。此外table.getColumnOffsets()會(huì)一次性構(gòu)建“全部 / 居中 / 起始固定 / 結(jié)束固定”四個(gè)區(qū)域的 start/after 偏移表ColumnOffsetsByPosition并以此支撐column.getStart()/column.getAfter()的 O(1) 查詢見 columnSizingFeature.utils.ts。偏移量的正確性直接影響固定列pinning場(chǎng)景下的布局。六、與columnSizing狀態(tài)、columnResizing的關(guān)系理解ColumnDef_ColumnSizing還需要分清它和另外兩個(gè)相鄰概念1.state.columnSizing已提交尺寸狀態(tài)類型為Recordstring, number以列 id 為鍵、像素?cái)?shù)為值見 columnSizingFeature.types.ts。它是“運(yùn)行時(shí)覆蓋層”優(yōu)先級(jí)高于columnDef.size。相關(guān) APItable.setColumnSizing(updater)—— 更新已提交尺寸table.resetColumnSizing(defaultState?)—— 重置為initialState.columnSizing或空對(duì)象column.resetSize()—— 只移除當(dāng)前列的尺寸覆蓋使其回退到columnDef.size與默認(rèn)值見 columnSizingFeature.utils.ts。column_resetSize的實(shí)現(xiàn)值得留意它遍歷當(dāng)前狀態(tài)僅剔除當(dāng)前列 id 的條目、保留其余列再通過(guò)onColumnSizingChange提交新狀態(tài)。2.columnResizing拖拽過(guò)程狀態(tài)ColumnDef_ColumnSizing只管“靜態(tài)約束”而實(shí)際拖拽行為由ColumnDef_ColumnResizing提供每個(gè)列定義還有一個(gè)enableResizing?: boolean開關(guān)表級(jí)選項(xiàng)enableColumnResizing、columnResizeModeonChange | onEnd、columnResizeDirectionltr | rtl則決定拖拽時(shí)的提交時(shí)機(jī)與方向見 columnResizingFeature.types.ts。拖拽過(guò)程中產(chǎn)生的臨時(shí)狀態(tài)columnSizingStart、deltaOffset、isResizingColumn等與最終提交到columnSizing的值是分離的onChange模式下拖拽過(guò)程會(huì)持續(xù)提交尺寸onEnd模式下拖拽結(jié)束才提交。無(wú)論哪種模式提交后的值最終都要經(jīng)過(guò)本文第三、四節(jié)所述的minSize/maxSize鉗制。七、實(shí)戰(zhàn)配置示例下面以本倉(cāng)庫(kù) examples/react/column-sizing 為代表的用法給出一個(gè)完整的列寬配置。這里以 React 風(fēng)格示意其余框架的 API 形態(tài)一致如 Vue、Solid、Svelte 的列定義均可使用同樣的三個(gè)屬性import { createColumnHelper } from tanstack/react-table type Person { id: string name: string email: string description: string } const columnHelper createColumnHelperPerson() const columns [ columnHelper.accessor(id, { size: 60, // 窄列初始 60px minSize: 40, // 最小 40px maxSize: 80, // 最大 80px保持固定感 }), columnHelper.accessor(name, { size: 180, minSize: 100, }), columnHelper.accessor(email, { size: 240, minSize: 160, }), columnHelper.accessor(description, { size: 320, minSize: 200, maxSize: 600, // 防止描述列無(wú)限拉伸 }), ]配套的表級(jí)配置const table useTable({ columns, data, enableColumnResizing: true, // 開啟列寬拖拽 columnResizeMode: onChange, // 拖拽過(guò)程中實(shí)時(shí)提交性能要求高可改 onEnd // state: { columnSizing: { name: 200 } }, // 外部受控寫法可覆蓋 columnDef.size })渲染列寬的方式在col或th/td上直接使用header.column.getSize()葉子列與header.getSize()分組表頭輸出像素寬度需要固定列偏移時(shí)使用column.getStart()/column.getAfter()需要整表總寬或固定區(qū)總寬時(shí)使用table.getTotalSize()等四個(gè) total 系列 API。八、常見問(wèn)題與最佳實(shí)踐為什么設(shè)置了size卻不生效檢查state.columnSizing或initialState.columnSizing中是否已存在該列的條目——狀態(tài)值優(yōu)先于size。需要恢復(fù)時(shí)調(diào)用column.resetSize()或table.resetColumnSizing()。列寬拖拽超過(guò)minSize/maxSize后仍顯示為邊界值這是正常現(xiàn)象column_getSize()的 clamp 保證解析結(jié)果永遠(yuǎn)落在[minSize, maxSize]區(qū)間內(nèi)。分組表頭的寬度總和與子列不一致分組表頭寬度是葉子列遞歸求和的結(jié)果修改任意葉子列寬后父表頭會(huì)同步重算若遇到不一致確認(rèn)列的visible狀態(tài)隱藏列不參與求和與columnSizing提交是否正確。固定列與列寬配合列寬偏移量getStart/getAfter依賴完整的可見列寬列表啟用columnPinning后三個(gè)固定區(qū)域會(huì)分別計(jì)算偏移與合計(jì)寬度配置列寬時(shí)需保證 min/max 區(qū)間與固定區(qū)域布局匹配。Feature 注冊(cè)前提本接口由columnSizingFeature提供。按照 docs/guide/features.md 的說(shuō)明TanStack Table v9 采用插件架構(gòu)只有注冊(cè)了該 featureColumnDef才具備size/minSize/maxSize三個(gè)屬性以及column.getSize()等 API未注冊(cè)時(shí) TypeScript 類型上也不會(huì)出現(xiàn)這些 API。九、源碼與測(cè)試索引如果想深入閱讀本文涉及的全部實(shí)現(xiàn)細(xì)節(jié)可以在本倉(cāng)庫(kù)中按以下路徑追蹤接口定義packages/table-core/src/features/column-sizing/columnSizingFeature.types.ts尺寸解析與鉗制算法packages/table-core/src/features/column-sizing/columnSizingFeature.utils.tsFeature 注冊(cè)與 memo 依賴packages/table-core/src/features/column-sizing/columnSizingFeature.ts拖拽相關(guān)選項(xiàng)enableResizing、columnResizeMode等packages/table-core/src/features/column-resizing/columnResizingFeature.types.ts單元測(cè)試覆蓋默認(rèn)值、clamp、reset、偏移量、分組重算等全部行為packages/table-core/tests/unit/features/column-sizing/columnSizingFeature.utils.test.ts框架示例examples/react/column-sizing相關(guān)指南docs/guide/columns.md、docs/guide/features.md掌握size/minSize/maxSize三者與columnSizing狀態(tài)的優(yōu)先級(jí)關(guān)系就能精準(zhǔn)控制每一列的初始寬度、伸縮邊界并理解列寬拖拽、固定列等復(fù)雜布局背后的解析原理。贊分享前端UI組件【免費(fèi)下載鏈接】table Headless UI for building powerful tables datagrids for TS/JS - React-Table, Vue-Table, Solid-Table, Svelte-Table項(xiàng)目地址https://gitcode.com/gh_mirrors/ta/table點(diǎn)擊查看免費(fèi)下載相關(guān)推薦深入解析 TanStack Table 的 ColumnOffsets 接口列偏移量與列寬定位的實(shí)現(xiàn)原理深入解析 TanStack Table 的 ColumnOffsets 接口列偏移量與列寬定位的實(shí)現(xiàn)原理 導(dǎo)讀 ColumnOffsets 是 TanStac前端UI組件TanStack Table 列級(jí)尺寸調(diào)整開關(guān)ColumnDef.enableResizing 接口詳解與列寬調(diào)整實(shí)戰(zhàn)TanStack Table 列級(jí)尺寸調(diào)整開關(guān)ColumnDef.enableResizing 接口詳解與列寬調(diào)整實(shí)戰(zhàn) 導(dǎo)讀 在 TanStack Table前端UI組件TanStack Table 列寬調(diào)整核心 API 深入解析Table_ColumnResizing 接口的 resetHeaderSizeInfo 與 setColumnResizingTanStack Table 列寬調(diào)整核心 API 深入解析Table_ColumnResizing 接口的 resetHeaderSizeInfo 與 se前端UI組件創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考