From 5b8056f24ac608a9092db7f8b03e2fb2e99101c8 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Tue, 28 Jul 2026 21:07:40 +0800 Subject: [PATCH 1/8] fix(vtable): fill auto height zero rows --- .../debug/issue-5115-auto-height-zero-row.ts | 65 +++++++++++++++++++ packages/vtable/examples/menu.ts | 4 ++ .../progress/create-group-for-first-screen.ts | 16 +++++ 3 files changed, 85 insertions(+) create mode 100644 packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts diff --git a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts new file mode 100644 index 0000000000..3f69b13d0f --- /dev/null +++ b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts @@ -0,0 +1,65 @@ +import * as VTable from '../../src'; + +const CONTAINER_ID = 'vTable'; + +const records = Array.from({ length: 120 }, (_, index) => ({ + id: index + 1, + status: index % 2 === 0 ? 'hidden-height-0' : 'visible', + text: `row ${index + 1} visible content` +})); + +export function createTable() { + const container = document.getElementById(CONTAINER_ID)!; + document.getElementById('issue5115Toolbar')?.remove(); + container.style.width = '720px'; + container.style.height = '420px'; + + const toolbar = document.createElement('div'); + toolbar.id = 'issue5115Toolbar'; + toolbar.style.cssText = 'height: 48px; font-size: 12px; display: flex; gap: 12px; align-items: center;'; + toolbar.innerHTML = ` + + + `; + container.before(toolbar); + + const tableInstance = new VTable.ListTable({ + container, + records, + columns: [ + { field: 'id', title: 'ID', width: 80 }, + { field: 'status', title: 'Status', width: 160 }, + { field: 'text', title: 'Text', width: 260 } + ], + widthMode: 'standard', + heightMode: 'autoHeight', + defaultRowHeight: 40, + customComputeRowHeight: ({ row }) => { + if (row > 0 && (row - 1) % 2 === 0) { + return 0; + } + return 'auto'; + } + }); + + const check = () => { + const proxy = tableInstance.scenegraph.proxy; + const bodyStart = tableInstance.frozenRowCount; + const bodyHeight = tableInstance.tableNoFrameHeight - tableInstance.getFrozenRowsHeight(); + const renderedHeight = tableInstance.getRowsHeight(bodyStart, proxy.rowEnd); + const zeroHeight = tableInstance.getRowHeight(tableInstance.columnHeaderLevelCount) === 0; + const pass = zeroHeight && renderedHeight >= bodyHeight; + const state = document.getElementById('issue5115State')!; + state.textContent = + `${pass ? 'PASS' : 'FAIL'} | zeroHeight=${zeroHeight} renderedHeight=${renderedHeight} ` + + `bodyHeight=${bodyHeight} rowEnd=${proxy.rowEnd}`; + return { pass, zeroHeight, renderedHeight, bodyHeight, rowEnd: proxy.rowEnd }; + }; + + document.getElementById('issue5115Check')!.addEventListener('click', check); + + window.tableInstance = tableInstance; + (window as any).issue5115Check = check; + + setTimeout(check, 0); +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index 13b2c16107..f435bad181 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -34,6 +34,10 @@ export const menus = [ path: 'debug', name: 'issue-5114' }, + { + path: 'debug', + name: 'issue-5115-auto-height-zero-row' + }, { path: 'debug', name: 'issue-5146' diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index 4fcf6d1baa..8927530a19 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -6,6 +6,21 @@ import { computeRowsHeight } from '../../layout/compute-row-height'; import { createColGroup } from '../column'; import type { SceneProxy } from './proxy'; +function fillVisibleBodyRows(proxy: SceneProxy, distRow: number): number { + const { table } = proxy; + const bodyBottomRow = table.rowCount - 1 - table.bottomFrozenRowCount; + const visibleBodyHeight = table.tableNoFrameHeight - table.getFrozenRowsHeight() - table.getBottomFrozenRowsHeight(); + let targetRow = distRow; + + while (targetRow < bodyBottomRow && table.getRowsHeight(table.frozenRowCount, targetRow) < visibleBodyHeight) { + const nextRow = targetRow + 1; + computeRowsHeight(table, targetRow + 1, nextRow); + targetRow = nextRow; + } + + return targetRow; +} + export function createGroupForFirstScreen( cornerHeaderGroup: Group, colHeaderGroup: Group, @@ -64,6 +79,7 @@ export function createGroupForFirstScreen( ? table.rowCount - 1 : distRowForCompute ?? distRow ); //如果配置了 canvasHeight为 'auto', 则一次性将所有行高都计算出来才能满足后续赋值表格高度的使用 + distRow = fillVisibleBodyRows(proxy, distRow); } if (distCol < table.colCount - table.rightFrozenColCount) { From 06cc55372be522928b2929afde28b407be2eb917 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 10:57:37 +0800 Subject: [PATCH 2/8] fix(vtable): limit zero-row fill to auto height --- .../group-creater/progress/create-group-for-first-screen.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index 8927530a19..ea0af67515 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -79,7 +79,9 @@ export function createGroupForFirstScreen( ? table.rowCount - 1 : distRowForCompute ?? distRow ); //如果配置了 canvasHeight为 'auto', 则一次性将所有行高都计算出来才能满足后续赋值表格高度的使用 - distRow = fillVisibleBodyRows(proxy, distRow); + if (table.heightMode === 'autoHeight') { + distRow = fillVisibleBodyRows(proxy, distRow); + } } if (distCol < table.colCount - table.rightFrozenColCount) { From 17c163cae36d270b6ba2f6f15c6b235caeb69194 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 11:10:44 +0800 Subject: [PATCH 3/8] fix(vtable): keep row height cache during zero fill --- .../group-creater/progress/create-group-for-first-screen.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index ea0af67515..f552cee718 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -14,7 +14,7 @@ function fillVisibleBodyRows(proxy: SceneProxy, distRow: number): number { while (targetRow < bodyBottomRow && table.getRowsHeight(table.frozenRowCount, targetRow) < visibleBodyHeight) { const nextRow = targetRow + 1; - computeRowsHeight(table, targetRow + 1, nextRow); + computeRowsHeight(table, nextRow, nextRow, false); targetRow = nextRow; } From eac5791fec86ad7b287b55a8bcf2f97f9bdee3d5 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 12:48:04 +0800 Subject: [PATCH 4/8] fix(vtable): align first screen body row range --- .../debug/issue-5115-auto-height-zero-row.ts | 4 +++- .../progress/create-group-for-first-screen.ts | 15 ++++++++------- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts index 3f69b13d0f..92e1bfb0b6 100644 --- a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts +++ b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts @@ -34,6 +34,7 @@ export function createTable() { widthMode: 'standard', heightMode: 'autoHeight', defaultRowHeight: 40, + bottomFrozenRowCount: 2, customComputeRowHeight: ({ row }) => { if (row > 0 && (row - 1) % 2 === 0) { return 0; @@ -45,7 +46,8 @@ export function createTable() { const check = () => { const proxy = tableInstance.scenegraph.proxy; const bodyStart = tableInstance.frozenRowCount; - const bodyHeight = tableInstance.tableNoFrameHeight - tableInstance.getFrozenRowsHeight(); + const bodyHeight = + tableInstance.tableNoFrameHeight - tableInstance.getFrozenRowsHeight() - tableInstance.getBottomFrozenRowsHeight(); const renderedHeight = tableInstance.getRowsHeight(bodyStart, proxy.rowEnd); const zeroHeight = tableInstance.getRowHeight(tableInstance.columnHeaderLevelCount) === 0; const pass = zeroHeight && renderedHeight >= bodyHeight; diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index f552cee718..0bf78f4ba5 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -65,6 +65,7 @@ export function createGroupForFirstScreen( } else { distRow = Math.min(proxy.firstScreenRowLimit - 1, table.rowCount - 1); } + let bodyDistRow = Math.min(proxy.bodyBottomRow, distRow - table.bottomFrozenRowCount); if (table.internalProps._widthResizedColMap.size === 0) { // compute colums width in first screen computeColsWidth(table, 0, distColForCompute ?? distCol); @@ -80,7 +81,7 @@ export function createGroupForFirstScreen( : distRowForCompute ?? distRow ); //如果配置了 canvasHeight为 'auto', 则一次性将所有行高都计算出来才能满足后续赋值表格高度的使用 if (table.heightMode === 'autoHeight') { - distRow = fillVisibleBodyRows(proxy, distRow); + bodyDistRow = fillVisibleBodyRows(proxy, bodyDistRow); } } @@ -90,7 +91,7 @@ export function createGroupForFirstScreen( computeColsWidth(table, table.colCount - table.rightFrozenColCount, table.colCount - 1); } } - if (distRow < table.rowCount - table.bottomFrozenRowCount) { + if (bodyDistRow < table.rowCount - table.bottomFrozenRowCount) { // compute bottom frozen row height if (table.rowCount - table.bottomFrozenRowCount <= table.rowCount - 1) { computeRowsHeight(table, table.rowCount - table.bottomFrozenRowCount, table.rowCount - 1); @@ -146,7 +147,7 @@ export function createGroupForFirstScreen( table.leftRowSeriesNumberCount - 1, // colEnd table.frozenRowCount, // rowStart // Math.min(proxy.firstScreenRowLimit, table.rowCount - 1 - table.bottomFrozenRowCount), // rowEnd - distRow - table.bottomFrozenRowCount, + bodyDistRow, 'rowHeader', // isHeader table ); @@ -160,7 +161,7 @@ export function createGroupForFirstScreen( Math.min(table.frozenColCount - 1, table.rowHeaderLevelCount + table.leftRowSeriesNumberCount - 1), // colEnd table.frozenRowCount, // rowStart // Math.min(proxy.firstScreenRowLimit, table.rowCount - 1 - table.bottomFrozenRowCount), // rowEnd - distRow - table.bottomFrozenRowCount, + bodyDistRow, 'rowHeader', // isHeader table ); @@ -174,7 +175,7 @@ export function createGroupForFirstScreen( table.frozenColCount - 1, // colEnd table.frozenRowCount, // rowStart // Math.min(proxy.firstScreenRowLimit, table.rowCount - 1 - table.bottomFrozenRowCount), // rowEnd - distRow - table.bottomFrozenRowCount, + bodyDistRow, 'body', table ); @@ -293,7 +294,7 @@ export function createGroupForFirstScreen( table.colCount - 1, // colEnd table.frozenRowCount, // rowStart // Math.min(proxy.firstScreenRowLimit, table.rowCount - 1 - table.bottomFrozenRowCount), // rowEnd - distRow - table.bottomFrozenRowCount, + bodyDistRow, table.isPivotChart() ? 'rowHeader' : 'body', // isHeader table ); @@ -325,7 +326,7 @@ export function createGroupForFirstScreen( distCol - table.rightFrozenColCount, table.frozenRowCount, // rowStart // Math.min(proxy.firstScreenRowLimit, table.rowCount - 1 - table.bottomFrozenRowCount), // rowEnd - distRow - table.bottomFrozenRowCount, + bodyDistRow, 'body', // isHeader table ); From 7ce351ef94743b839874099176ac7d2c3509ee30 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 15:49:27 +0800 Subject: [PATCH 5/8] fix(vtable): fill auto height rows after tree toggle --- .../debug/issue-5115-auto-height-zero-row.ts | 87 ++++++++++++++----- .../src/scenegraph/layout/update-row.ts | 40 +++++++++ 2 files changed, 107 insertions(+), 20 deletions(-) diff --git a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts index 92e1bfb0b6..ea5d5efcfd 100644 --- a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts +++ b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts @@ -2,11 +2,36 @@ import * as VTable from '../../src'; const CONTAINER_ID = 'vTable'; -const records = Array.from({ length: 120 }, (_, index) => ({ - id: index + 1, - status: index % 2 === 0 ? 'hidden-height-0' : 'visible', - text: `row ${index + 1} visible content` +const filteredChildren = Array.from({ length: 300 }, (_, index) => ({ + name: `filtered child ${index + 1}`, + status: 'visible before filter', + desc: 'This row is hidden after filter interaction', + _show: true })); +const visibleChildren = Array.from({ length: 40 }, (_, index) => ({ + name: `visible child ${index + 1}`, + status: 'visible after filter', + desc: `Visible tree row ${index + 1} should fill the viewport after filtered zero-height rows`, + _show: true +})); +const records = [ + { + name: 'expanded group filtered by interaction', + status: 'group', + desc: 'Children below become _show=false after simulated filter interaction', + _show: true, + hierarchyState: 'expand', + children: filteredChildren + }, + { + name: 'expanded group with visible children', + status: 'group', + desc: 'These rows should be pulled into first screen after zero-height rows', + _show: true, + hierarchyState: 'expand', + children: visibleChildren + } +]; export function createTable() { const container = document.getElementById(CONTAINER_ID)!; @@ -19,29 +44,30 @@ export function createTable() { toolbar.style.cssText = 'height: 48px; font-size: 12px; display: flex; gap: 12px; align-items: center;'; toolbar.innerHTML = ` + `; container.before(toolbar); - const tableInstance = new VTable.ListTable({ + const option: VTable.ListTableConstructorOptions = { container, records, columns: [ - { field: 'id', title: 'ID', width: 80 }, - { field: 'status', title: 'Status', width: 160 }, - { field: 'text', title: 'Text', width: 260 } + { field: 'name', title: 'Name', tree: true, width: 260 }, + { field: 'status', title: 'Status', width: 180 }, + { field: 'desc', title: 'Description', width: 260 } ], widthMode: 'standard', heightMode: 'autoHeight', defaultRowHeight: 40, - bottomFrozenRowCount: 2, - customComputeRowHeight: ({ row }) => { - if (row > 0 && (row - 1) % 2 === 0) { - return 0; - } - return 'auto'; + hierarchyIndent: 20, + hierarchyExpandLevel: 2, + customComputeRowHeight: ({ row, table }) => { + const record = table.getCellOriginRecord(0, row); + return record && record._show === false ? 0 : 'auto'; } - }); + }; + const tableInstance = new VTable.ListTable(option); const check = () => { const proxy = tableInstance.scenegraph.proxy; @@ -49,19 +75,40 @@ export function createTable() { const bodyHeight = tableInstance.tableNoFrameHeight - tableInstance.getFrozenRowsHeight() - tableInstance.getBottomFrozenRowsHeight(); const renderedHeight = tableInstance.getRowsHeight(bodyStart, proxy.rowEnd); - const zeroHeight = tableInstance.getRowHeight(tableInstance.columnHeaderLevelCount) === 0; - const pass = zeroHeight && renderedHeight >= bodyHeight; + const firstFilteredRowHeight = tableInstance.getRowHeight(tableInstance.columnHeaderLevelCount + 1); + const pass = firstFilteredRowHeight === 0 && renderedHeight >= bodyHeight; const state = document.getElementById('issue5115State')!; state.textContent = - `${pass ? 'PASS' : 'FAIL'} | zeroHeight=${zeroHeight} renderedHeight=${renderedHeight} ` + + `${pass ? 'PASS' : 'FAIL'} | firstFilteredRowHeight=${firstFilteredRowHeight} renderedHeight=${renderedHeight} ` + `bodyHeight=${bodyHeight} rowEnd=${proxy.rowEnd}`; - return { pass, zeroHeight, renderedHeight, bodyHeight, rowEnd: proxy.rowEnd }; + return { pass, firstFilteredRowHeight, renderedHeight, bodyHeight, rowEnd: proxy.rowEnd }; + }; + + const filterRows = () => { + filteredChildren.forEach(record => { + record._show = false; + record.status = 'hidden by _show=false'; + }); + tableInstance.updateOption(option, { clearRowHeightCache: true, clearColWidthCache: false }); + }; + + const toggleCheck = async () => { + tableInstance.toggleHierarchyState(0, 1, false); + await new Promise(resolve => setTimeout(resolve, 60)); + tableInstance.toggleHierarchyState(0, 1, false); + await new Promise(resolve => setTimeout(resolve, 120)); + return check(); }; document.getElementById('issue5115Check')!.addEventListener('click', check); + document.getElementById('issue5115ToggleCheck')!.addEventListener('click', toggleCheck); window.tableInstance = tableInstance; (window as any).issue5115Check = check; + (window as any).issue5115ToggleCheck = toggleCheck; - setTimeout(check, 0); + setTimeout(() => { + filterRows(); + setTimeout(check, 0); + }, 0); } diff --git a/packages/vtable/src/scenegraph/layout/update-row.ts b/packages/vtable/src/scenegraph/layout/update-row.ts index a2175ff157..610bbcefa5 100644 --- a/packages/vtable/src/scenegraph/layout/update-row.ts +++ b/packages/vtable/src/scenegraph/layout/update-row.ts @@ -7,6 +7,7 @@ import type { Scenegraph } from '../scenegraph'; import { getCellMergeInfo } from '../utils/get-cell-merge'; import { deduplication } from '../../tools/util'; import { checkHaveTextStick, resetTextStick } from '../stick-text'; +import { computeRowsHeight } from './compute-row-height'; /** * add and remove rows in scenegraph @@ -78,6 +79,11 @@ export function updateRow( updateAfter = updateAfter ?? needUpdateAfter; rowHeightsMap.insert(row); }); + const filledVisibleRowStart = fillVisibleBodyRows(scene); + if (isNumber(filledVisibleRowStart)) { + updateAfter = updateAfter ?? filledVisibleRowStart; + rowUpdatePos = isValid(rowUpdatePos) ? Math.min(rowUpdatePos, filledVisibleRowStart) : filledVisibleRowStart; + } // reset attribute y and row number in CellGroup // const newTotalHeight = resetRowNumberAndY(scene); @@ -277,6 +283,40 @@ function addRow(row: number, scene: Scenegraph, skipUpdateProxy?: boolean) { // scene.proxy.rowEnd++; // scene.proxy.currentRow++; } + +function fillVisibleBodyRows(scene: Scenegraph): number | undefined { + const { table, proxy } = scene; + if (table.heightMode !== 'autoHeight') { + return undefined; + } + const bodyBottomRow = table.rowCount - 1 - table.bottomFrozenRowCount; + const visibleBodyHeight = table.tableNoFrameHeight - table.getFrozenRowsHeight() - table.getBottomFrozenRowsHeight(); + let targetRow = Math.min(proxy.rowEnd, bodyBottomRow); + + computeRowsHeight(table, proxy.rowStart, targetRow, false); + while (targetRow < bodyBottomRow && table.getRowsHeight(table.frozenRowCount, targetRow) < visibleBodyHeight) { + const nextRow = targetRow + 1; + computeRowsHeight(table, nextRow, nextRow, false); + targetRow = nextRow; + } + + if (targetRow <= proxy.rowEnd) { + return undefined; + } + + const startRow = proxy.rowEnd + 1; + for (let row = startRow; row <= targetRow; row++) { + addRowCellGroup(row, scene); + } + proxy.rowEnd = targetRow; + proxy.currentRow = Math.max(proxy.currentRow, targetRow); + proxy.totalRow = Math.max(proxy.totalRow, targetRow); + proxy.totalActualBodyRowCount = Math.max(proxy.totalActualBodyRowCount, targetRow - proxy.rowStart + 1); + proxy.rowUpdatePos = Math.min(proxy.rowUpdatePos, startRow); + + return startRow; +} + function resetRowNumber(scene: Scenegraph) { scene.bodyGroup.forEachChildren((colGroup: Group) => { let rowIndex = scene.bodyRowStart; From deeffba5fefe6a40991cf232319f72bbb046990d Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 16:20:18 +0800 Subject: [PATCH 6/8] fix(vtable): sync record index checkbox cascade state --- .../vtable/src/state/checkbox/checkbox.ts | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/packages/vtable/src/state/checkbox/checkbox.ts b/packages/vtable/src/state/checkbox/checkbox.ts index 92a183134f..5b4da0ea5e 100644 --- a/packages/vtable/src/state/checkbox/checkbox.ts +++ b/packages/vtable/src/state/checkbox/checkbox.ts @@ -6,6 +6,9 @@ import type { BaseTableAPI } from '../../ts-types/base-table'; import type { CachedDataSource } from '../../data'; import type { CheckBox } from '@src/vrender'; +type CheckboxStateValue = boolean | 'indeterminate'; +type CheckboxRecordValue = CheckboxStateValue | { checked?: CheckboxStateValue }; + export function setCheckedState( col: number, row: number, @@ -590,9 +593,12 @@ function updateParentCheckboxStateByRecordIndex(recordIndex: number | number[], continue; } - const childStates = parentRecord.children.map((child: any, childIndex: number) => - getRecordCheckboxState(parentIndex.concat(childIndex), child, field, table) - ); + const childStates: CheckboxStateValue[] = parentRecord.children.map((child: any, childIndex: number) => { + const childRecordIndex = parentIndex.concat(childIndex); + const childState = getRecordCheckboxState(childRecordIndex, child, field, table); + setRecordCheckboxState(childRecordIndex, field, childState, table.stateManager.checkedState); + return childState; + }); const allChecked = childStates.every(state => state === true); const allUnchecked = childStates.every(state => state !== true && state !== 'indeterminate'); const parentState = allChecked ? true : allUnchecked ? false : 'indeterminate'; @@ -606,7 +612,7 @@ function getRecordCheckboxState( record: any, field: FieldDef, table: BaseTableAPI -): boolean | 'indeterminate' { +): CheckboxStateValue { const fieldKey = field as string | number; const dataIndex = normalizeRecordIndex(recordIndex).toString(); const cachedState = table.stateManager.checkedState.get(dataIndex)?.[fieldKey]; @@ -614,9 +620,9 @@ function getRecordCheckboxState( return cachedState; } - const value = record?.[fieldKey]; - if (isObject(value) && isValid(value.checked)) { - return value.checked; + const value = record?.[fieldKey] as CheckboxRecordValue | undefined; + if (isObject(value) && isValid((value as { checked?: CheckboxStateValue }).checked)) { + return (value as { checked?: CheckboxStateValue }).checked; } if (typeof value === 'boolean') { return value; From 8ad8e8923901ade52211e896f33353156681e0cf Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 16:54:11 +0800 Subject: [PATCH 7/8] fix(vtable): sync auto height first screen rows --- .../debug/issue-5115-auto-height-zero-row.ts | 17 ++++++++++++++--- .../progress/create-group-for-first-screen.ts | 10 ++++++++++ 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts index ea5d5efcfd..88b1877e06 100644 --- a/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts +++ b/packages/vtable/examples/debug/issue-5115-auto-height-zero-row.ts @@ -76,12 +76,23 @@ export function createTable() { tableInstance.tableNoFrameHeight - tableInstance.getFrozenRowsHeight() - tableInstance.getBottomFrozenRowsHeight(); const renderedHeight = tableInstance.getRowsHeight(bodyStart, proxy.rowEnd); const firstFilteredRowHeight = tableInstance.getRowHeight(tableInstance.columnHeaderLevelCount + 1); - const pass = firstFilteredRowHeight === 0 && renderedHeight >= bodyHeight; + const proxyRowsSynced = + proxy.totalRow >= proxy.rowEnd && proxy.totalActualBodyRowCount >= proxy.rowEnd - proxy.rowStart + 1; + const pass = firstFilteredRowHeight === 0 && renderedHeight >= bodyHeight && proxyRowsSynced; const state = document.getElementById('issue5115State')!; state.textContent = `${pass ? 'PASS' : 'FAIL'} | firstFilteredRowHeight=${firstFilteredRowHeight} renderedHeight=${renderedHeight} ` + - `bodyHeight=${bodyHeight} rowEnd=${proxy.rowEnd}`; - return { pass, firstFilteredRowHeight, renderedHeight, bodyHeight, rowEnd: proxy.rowEnd }; + `bodyHeight=${bodyHeight} rowEnd=${proxy.rowEnd} totalRow=${proxy.totalRow}`; + return { + pass, + firstFilteredRowHeight, + renderedHeight, + bodyHeight, + rowEnd: proxy.rowEnd, + totalRow: proxy.totalRow, + totalActualBodyRowCount: proxy.totalActualBodyRowCount, + proxyRowsSynced + }; }; const filterRows = () => { diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index 0bf78f4ba5..651072cbf3 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -21,6 +21,15 @@ function fillVisibleBodyRows(proxy: SceneProxy, distRow: number): number { return targetRow; } +function syncVisibleBodyRows(proxy: SceneProxy, targetRow: number) { + if (targetRow <= proxy.totalRow) { + return; + } + + proxy.totalRow = targetRow; + proxy.totalActualBodyRowCount = Math.max(proxy.totalActualBodyRowCount, targetRow - proxy.bodyTopRow + 1); +} + export function createGroupForFirstScreen( cornerHeaderGroup: Group, colHeaderGroup: Group, @@ -82,6 +91,7 @@ export function createGroupForFirstScreen( ); //如果配置了 canvasHeight为 'auto', 则一次性将所有行高都计算出来才能满足后续赋值表格高度的使用 if (table.heightMode === 'autoHeight') { bodyDistRow = fillVisibleBodyRows(proxy, bodyDistRow); + syncVisibleBodyRows(proxy, bodyDistRow); } } From 87ebd12c09b0431d828ec5577016079731cdeae3 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Wed, 29 Jul 2026 17:45:39 +0800 Subject: [PATCH 8/8] fix(vtable): preserve bottom frozen height timing --- .../group-creater/progress/create-group-for-first-screen.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts index 651072cbf3..01b31ddeb1 100644 --- a/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts +++ b/packages/vtable/src/scenegraph/group-creater/progress/create-group-for-first-screen.ts @@ -101,7 +101,7 @@ export function createGroupForFirstScreen( computeColsWidth(table, table.colCount - table.rightFrozenColCount, table.colCount - 1); } } - if (bodyDistRow < table.rowCount - table.bottomFrozenRowCount) { + if (distRow < table.rowCount - table.bottomFrozenRowCount) { // compute bottom frozen row height if (table.rowCount - table.bottomFrozenRowCount <= table.rowCount - 1) { computeRowsHeight(table, table.rowCount - table.bottomFrozenRowCount, table.rowCount - 1);