From 8c4f8af8c9ad4445e9a27f7ca695a7b5c7c785ab Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 30 Jul 2026 13:17:58 +0800 Subject: [PATCH 1/3] fix(vtable): reset reused icon opacity by visible time --- .../issue-4798-sort-icon-visible-time.ts | 100 ++++++++++++++++++ packages/vtable/examples/menu.ts | 4 + .../src/scenegraph/utils/text-icon-layout.ts | 2 + 3 files changed, 106 insertions(+) create mode 100644 packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts diff --git a/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts new file mode 100644 index 0000000000..8bb1e25f5a --- /dev/null +++ b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts @@ -0,0 +1,100 @@ +import * as VTable from '../../src'; + +const CONTAINER_ID = 'vTable'; + +const sortIconBase = { + type: 'text' as const, + width: 16, + height: 16, + funcType: VTable.TYPES.IconFuncTypeEnum.sort, + positionType: VTable.TYPES.IconPosition.absoluteRight, + marginRight: 8, + cursor: 'pointer' +}; + +function registerSortIcons() { + VTable.register.icon('sort_normal', { + ...sortIconBase, + name: 'sort_normal', + content: 'N', + visibleTime: 'mouseenter_cell', + style: { + fill: '#999' + } + }); + VTable.register.icon('sort_upward', { + ...sortIconBase, + name: 'sort_upward', + content: 'A', + visibleTime: 'always', + style: { + fill: '#1677ff' + } + }); + VTable.register.icon('sort_downward', { + ...sortIconBase, + name: 'sort_downward', + content: 'D', + visibleTime: 'always', + style: { + fill: '#1677ff' + } + }); +} + +function getSortIconState(tableInstance: VTable.ListTable) { + let state: any = null; + tableInstance.scenegraph.getCell(0, 0).forEachChildren((mark: any) => { + if (mark.attribute?.funcType === VTable.TYPES.IconFuncTypeEnum.sort) { + state = { + name: mark.name, + visibleTime: mark.attribute.visibleTime, + opacity: mark.attribute.opacity + }; + } + }); + return state; +} + +function showCurrentSortIcon(tableInstance: VTable.ListTable) { + tableInstance.scenegraph.getCell(0, 0).forEachChildren((mark: any) => { + if (mark.attribute?.funcType === VTable.TYPES.IconFuncTypeEnum.sort) { + mark.setAttribute('opacity', 1); + } + }); +} + +export function createTable() { + registerSortIcons(); + + const container = document.getElementById(CONTAINER_ID)!; + container.style.width = '600px'; + container.style.height = '360px'; + + const tableInstance = new VTable.ListTable({ + container, + records: [ + { id: 1, name: 'Alice' }, + { id: 2, name: 'Bob' }, + { id: 3, name: 'Carol' } + ], + columns: [ + { field: 'id', title: 'ID', width: 120, sort: true }, + { field: 'name', title: 'Name', width: 200 } + ] + }); + + window.tableInstance = tableInstance; + (window as any).issue4798GetSortIconState = () => getSortIconState(tableInstance); + (window as any).issue4798CycleSort = () => { + showCurrentSortIcon(tableInstance); + const shownNormal = getSortIconState(tableInstance); + tableInstance.updateSortState({ field: 'id', order: 'asc' }); + const asc = getSortIconState(tableInstance); + tableInstance.updateSortState({ field: 'id', order: 'desc' }); + const desc = getSortIconState(tableInstance); + tableInstance.updateSortState(null); + const normal = getSortIconState(tableInstance); + return { shownNormal, asc, desc, normal }; + }; +} diff --git a/packages/vtable/examples/menu.ts b/packages/vtable/examples/menu.ts index d339e67072..71d7f7a744 100644 --- a/packages/vtable/examples/menu.ts +++ b/packages/vtable/examples/menu.ts @@ -74,6 +74,10 @@ export const menus = [ path: 'debug', name: 'issue-4816-functional-icons-theme' }, + { + path: 'debug', + name: 'issue-4798-sort-icon-visible-time' + }, { path: 'debug', name: 'header-frame-border-null-color' diff --git a/packages/vtable/src/scenegraph/utils/text-icon-layout.ts b/packages/vtable/src/scenegraph/utils/text-icon-layout.ts index 285c09f804..82d1903c88 100644 --- a/packages/vtable/src/scenegraph/utils/text-icon-layout.ts +++ b/packages/vtable/src/scenegraph/utils/text-icon-layout.ts @@ -539,6 +539,8 @@ export function dealWithIcon( iconAttribute.funcType = icon.funcType; iconAttribute.interactive = icon.interactive; iconAttribute.isGif = (icon as any).isGif; + iconAttribute.opacity = + iconAttribute.visibleTime === 'mouseenter_cell' || iconAttribute.visibleTime === 'click_cell' ? 0 : 1; let hierarchyOffset = 0; if ( From 9915ee4327b223d5e713cc3ddd472c355414a87e Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 30 Jul 2026 14:07:16 +0800 Subject: [PATCH 2/3] fix(vtable): update reused text icon attributes --- .../debug/issue-4798-sort-icon-visible-time.ts | 2 ++ .../src/scenegraph/utils/text-icon-layout.ts | 18 +++++++++++++----- 2 files changed, 15 insertions(+), 5 deletions(-) diff --git a/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts index 8bb1e25f5a..3faf1d3c3a 100644 --- a/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts +++ b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts @@ -48,6 +48,8 @@ function getSortIconState(tableInstance: VTable.ListTable) { if (mark.attribute?.funcType === VTable.TYPES.IconFuncTypeEnum.sort) { state = { name: mark.name, + text: mark.attribute.text, + fill: mark.attribute.fill, visibleTime: mark.attribute.visibleTime, opacity: mark.attribute.opacity }; diff --git a/packages/vtable/src/scenegraph/utils/text-icon-layout.ts b/packages/vtable/src/scenegraph/utils/text-icon-layout.ts index 82d1903c88..8920f0b7d8 100644 --- a/packages/vtable/src/scenegraph/utils/text-icon-layout.ts +++ b/packages/vtable/src/scenegraph/utils/text-icon-layout.ts @@ -539,8 +539,6 @@ export function dealWithIcon( iconAttribute.funcType = icon.funcType; iconAttribute.interactive = icon.interactive; iconAttribute.isGif = (icon as any).isGif; - iconAttribute.opacity = - iconAttribute.visibleTime === 'mouseenter_cell' || iconAttribute.visibleTime === 'click_cell' ? 0 : 1; let hierarchyOffset = 0; if ( @@ -585,9 +583,21 @@ export function dealWithIcon( iconAttribute.shape = icon.shape; } + if (icon.type === 'text') { + iconAttribute.text = icon.content; + merge(iconAttribute, icon.style); + } + + if (isNil(iconAttribute.opacity)) { + iconAttribute.opacity = + iconAttribute.visibleTime === 'mouseenter_cell' || iconAttribute.visibleTime === 'click_cell' ? 0 : 1; + } + if (mark) { mark.setAttributes(iconAttribute); - mark.loadImage(iconAttribute.image); + if (iconAttribute.image) { + mark.loadImage(iconAttribute.image); + } mark.tooltip = icon.tooltip; mark.name = icon.name; return mark; @@ -596,8 +606,6 @@ export function dealWithIcon( let iconMark: Icon | TextIcon; if (icon.type === 'text') { - iconAttribute.text = icon.content; - merge(iconAttribute, icon.style); iconMark = new TextIcon(iconAttribute); iconMark.tooltip = icon.tooltip; iconMark.name = icon.name; From 90c39098c46162a71fa36cc313eb04336f3dce38 Mon Sep 17 00:00:00 2001 From: fangsmile <892739385@qq.com> Date: Thu, 30 Jul 2026 15:27:13 +0800 Subject: [PATCH 3/3] test(vtable): align sort icon visibility demo --- .../issue-4798-sort-icon-visible-time.ts | 68 +++++++++++-------- 1 file changed, 38 insertions(+), 30 deletions(-) diff --git a/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts index 3faf1d3c3a..ae2ceb79ac 100644 --- a/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts +++ b/packages/vtable/examples/debug/issue-4798-sort-icon-visible-time.ts @@ -16,35 +16,38 @@ function registerSortIcons() { VTable.register.icon('sort_normal', { ...sortIconBase, name: 'sort_normal', - content: 'N', + content: '-', visibleTime: 'mouseenter_cell', style: { - fill: '#999' + fill: '#999', + fontWeight: 'bold' } }); VTable.register.icon('sort_upward', { ...sortIconBase, name: 'sort_upward', - content: 'A', + content: '^', visibleTime: 'always', style: { - fill: '#1677ff' + fill: '#1677ff', + fontWeight: 'bold' } }); VTable.register.icon('sort_downward', { ...sortIconBase, name: 'sort_downward', - content: 'D', + content: 'v', visibleTime: 'always', style: { - fill: '#1677ff' + fill: '#f5222d', + fontWeight: 'bold' } }); } -function getSortIconState(tableInstance: VTable.ListTable) { +function getSortIconState(tableInstance: VTable.ListTable, col: number) { let state: any = null; - tableInstance.scenegraph.getCell(0, 0).forEachChildren((mark: any) => { + tableInstance.scenegraph.getCell(col, 0).forEachChildren((mark: any) => { if (mark.attribute?.funcType === VTable.TYPES.IconFuncTypeEnum.sort) { state = { name: mark.name, @@ -58,14 +61,6 @@ function getSortIconState(tableInstance: VTable.ListTable) { return state; } -function showCurrentSortIcon(tableInstance: VTable.ListTable) { - tableInstance.scenegraph.getCell(0, 0).forEachChildren((mark: any) => { - if (mark.attribute?.funcType === VTable.TYPES.IconFuncTypeEnum.sort) { - mark.setAttribute('opacity', 1); - } - }); -} - export function createTable() { registerSortIcons(); @@ -76,27 +71,40 @@ export function createTable() { const tableInstance = new VTable.ListTable({ container, records: [ - { id: 1, name: 'Alice' }, - { id: 2, name: 'Bob' }, - { id: 3, name: 'Carol' } + { id: 1, name: 'Alice', score: 91 }, + { id: 2, name: 'Bob', score: 85 }, + { id: 3, name: 'Carol', score: 96 } ], columns: [ { field: 'id', title: 'ID', width: 120, sort: true }, - { field: 'name', title: 'Name', width: 200 } + { field: 'name', title: 'Name', width: 200, sort: true }, + { field: 'score', title: 'Score', width: 120 } ] }); window.tableInstance = tableInstance; - (window as any).issue4798GetSortIconState = () => getSortIconState(tableInstance); - (window as any).issue4798CycleSort = () => { - showCurrentSortIcon(tableInstance); - const shownNormal = getSortIconState(tableInstance); + (window as any).issue4798GetSortIconState = (col = 0) => getSortIconState(tableInstance, col); + (window as any).issue4798Run = () => { tableInstance.updateSortState({ field: 'id', order: 'asc' }); - const asc = getSortIconState(tableInstance); - tableInstance.updateSortState({ field: 'id', order: 'desc' }); - const desc = getSortIconState(tableInstance); - tableInstance.updateSortState(null); - const normal = getSortIconState(tableInstance); - return { shownNormal, asc, desc, normal }; + const firstAsc = getSortIconState(tableInstance, 0); + tableInstance.updateSortState({ field: 'name', order: 'asc' }); + const firstNormalAfterSecondSort = getSortIconState(tableInstance, 0); + const secondAsc = getSortIconState(tableInstance, 1); + return { + firstAsc, + firstNormalAfterSecondSort, + secondAsc, + fixed: + firstNormalAfterSecondSort?.name === 'sort_normal' && + firstNormalAfterSecondSort?.text === '-' && + firstNormalAfterSecondSort?.fill === '#999' && + firstNormalAfterSecondSort?.visibleTime === 'mouseenter_cell' && + firstNormalAfterSecondSort?.opacity === 0 && + secondAsc?.name === 'sort_upward' && + secondAsc?.text === '^' && + secondAsc?.fill === '#1677ff' && + secondAsc?.visibleTime === 'always' && + secondAsc?.opacity === 1 + }; }; }