Skip to content

Commit e35bec4

Browse files
authored
Merge pull request #5087 from VisActor/fix/resize-col-line-stuck-4120
Fix/resize col line stuck 4120
2 parents 3bb542e + 356693c commit e35bec4

7 files changed

Lines changed: 158 additions & 0 deletions

File tree

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{
2+
"changes": [
3+
{
4+
"comment": "fix: reset all interaction states on data update to avoid stale resize indicators",
5+
"type": "patch",
6+
"packageName": "@visactor/vtable"
7+
}
8+
],
9+
"packageName": "@visactor/vtable",
10+
"email": "2779428708@qq.com"
11+
}
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
import * as VTable from '../../src';
2+
import { bindDebugTool } from '../../src/scenegraph/debug-tool';
3+
const ListTable = VTable.ListTable;
4+
const CONTAINER_ID = 'vTable';
5+
6+
/**
7+
* 验证场景:列宽/行高调整过程中调用 setRecords 或 updateOption 时,
8+
* 调整指示线应被正确清除,不会残留在表格上。
9+
* 对应 issue: https://github.com/VisActor/VTable/issues/4120
10+
*
11+
* 复现步骤:
12+
* 1. 点击"自动定时刷新"按钮开启每3秒自动 setRecords
13+
* 2. 拖动列头边界开始调整列宽(鼠标按住不放)
14+
* 3. 等待自动刷新触发(或手动点击按钮)
15+
* 4. 修复前:指示线会卡在表格上无法消失
16+
* 5. 修复后:指示线在 setRecords/updateOption 调用时被正确清除
17+
*/
18+
export function createTable() {
19+
const generatePersons = (count: number) => {
20+
return Array.from(new Array(count)).map((_, i) => ({
21+
id: i + 1,
22+
name: `员工${i + 1}`,
23+
email: `user${i + 1}@example.com`,
24+
department: ['研发部', '市场部', '设计部', '产品部', '运营部'][i % 5],
25+
salary: Math.round(Math.random() * 10000 + 5000),
26+
city: ['北京', '上海', '广州', '深圳', '杭州'][i % 5]
27+
}));
28+
};
29+
30+
let records = generatePersons(100);
31+
32+
const columns: VTable.ColumnsDefine = [
33+
{ field: 'id', title: 'ID', width: 80 },
34+
{ field: 'name', title: '姓名', width: 120 },
35+
{ field: 'email', title: '邮箱', width: 220 },
36+
{ field: 'department', title: '部门', width: 120 },
37+
{ field: 'salary', title: '薪资', width: 120 },
38+
{ field: 'city', title: '城市', width: 120 }
39+
];
40+
41+
const option: VTable.ListTableConstructorOptions = {
42+
container: document.getElementById(CONTAINER_ID),
43+
records,
44+
columns,
45+
widthMode: 'standard',
46+
defaultRowHeight: 40,
47+
defaultHeaderRowHeight: 50,
48+
theme: VTable.themes.ARCO
49+
};
50+
51+
const btnContainer = document.createElement('div');
52+
btnContainer.style.cssText = 'padding: 10px 0; display: flex; gap: 10px; align-items: center; flex-wrap: wrap;';
53+
54+
const tip = document.createElement('span');
55+
tip.style.cssText = 'color: #666; font-size: 13px;';
56+
tip.textContent = '操作:先拖动列边界调整列宽,拖动过程中点击下方按钮';
57+
btnContainer.appendChild(tip);
58+
59+
const btnSetRecords = document.createElement('button');
60+
btnSetRecords.textContent = 'setRecords (刷新数据)';
61+
btnSetRecords.style.cssText =
62+
'padding: 6px 16px; cursor: pointer; background: #416EFF; color: #fff; border: none; border-radius: 4px;';
63+
btnSetRecords.addEventListener('click', () => {
64+
records = generatePersons(100);
65+
instance.setRecords(records);
66+
console.log('setRecords called');
67+
});
68+
btnContainer.appendChild(btnSetRecords);
69+
70+
const btnUpdateOption = document.createElement('button');
71+
btnUpdateOption.textContent = 'updateOption (更新配置)';
72+
btnUpdateOption.style.cssText =
73+
'padding: 6px 16px; cursor: pointer; background: #52C41A; color: #fff; border: none; border-radius: 4px;';
74+
btnUpdateOption.addEventListener('click', () => {
75+
records = generatePersons(100);
76+
instance.updateOption({
77+
...option,
78+
records
79+
});
80+
console.log('updateOption called');
81+
});
82+
btnContainer.appendChild(btnUpdateOption);
83+
84+
let timer: any = null;
85+
const btnAutoTest = document.createElement('button');
86+
btnAutoTest.textContent = '自动定时刷新 (每3秒)';
87+
btnAutoTest.style.cssText =
88+
'padding: 6px 16px; cursor: pointer; background: #FA8C16; color: #fff; border: none; border-radius: 4px;';
89+
btnAutoTest.addEventListener('click', () => {
90+
if (timer) {
91+
clearInterval(timer);
92+
timer = null;
93+
btnAutoTest.textContent = '自动定时刷新 (每3秒)';
94+
btnAutoTest.style.background = '#FA8C16';
95+
} else {
96+
timer = setInterval(() => {
97+
records = generatePersons(100);
98+
instance.setRecords(records);
99+
console.log('auto setRecords triggered');
100+
}, 3000);
101+
btnAutoTest.textContent = '停止自动刷新';
102+
btnAutoTest.style.background = '#FF4D4F';
103+
}
104+
});
105+
btnContainer.appendChild(btnAutoTest);
106+
107+
document.getElementById(CONTAINER_ID)?.before(btnContainer);
108+
109+
const instance = new ListTable(option);
110+
111+
bindDebugTool(instance.scenegraph.stage as any, {
112+
customGrapicKeys: ['role', '_updateTag']
113+
});
114+
115+
const originalRelease = instance.release.bind(instance);
116+
instance.release = () => {
117+
if (timer) {
118+
clearInterval(timer);
119+
timer = null;
120+
}
121+
btnContainer.remove();
122+
originalRelease();
123+
};
124+
125+
(window as any).tableInstance = instance;
126+
}

packages/vtable/examples/menu.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,6 +851,10 @@ export const menus = [
851851
path: 'interactive',
852852
name: 'row-resize'
853853
},
854+
{
855+
path: 'interactive',
856+
name: 'resize-setRecords'
857+
},
854858
{
855859
path: 'interactive',
856860
name: 'pre-sort'

packages/vtable/src/ListTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1546,6 +1546,7 @@ export class ListTable extends BaseTable implements ListTableAPI {
15461546
* @param option 附近参数,其中的sortState为排序状态,如果设置null 将清除目前的排序状态
15471547
*/
15481548
setRecords(records: Array<any>, option?: { sortState?: SortState | SortState[] | null }): void {
1549+
this.stateManager.endResizeIfResizing();
15491550
clearChartRenderQueue();
15501551
// 释放事件 及 对象
15511552
this.internalProps.dataSource?.release();

packages/vtable/src/PivotChart.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ export class PivotChart extends BaseTable implements PivotChartAPI {
16231623
* @param sort
16241624
*/
16251625
setRecords(records: Array<any>): void {
1626+
this.stateManager.endResizeIfResizing();
16261627
this.internalProps.layoutMap.release();
16271628
clearChartRenderQueue();
16281629
this.scenegraph.updateChartState(null, undefined);

packages/vtable/src/PivotTable.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,7 @@ export class PivotTable extends BaseTable implements PivotTableAPI {
16651665
* @param sort
16661666
*/
16671667
setRecords(records: Array<any>): void {
1668+
this.stateManager.endResizeIfResizing();
16681669
clearChartRenderQueue();
16691670
const oldHoverState = { col: this.stateManager.hover.cellPos.col, row: this.stateManager.hover.cellPos.row };
16701671
this.options.records = this.internalProps.records = records;

packages/vtable/src/state/state.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,21 @@ export class StateManager {
250250
this.setSelectState();
251251
this.setFrozenState();
252252
}
253+
endResizeIfResizing() {
254+
if (this.columnResize.resizing) {
255+
this.table.scenegraph.component.hideResizeCol();
256+
this.columnResize.resizing = false;
257+
}
258+
if (this.rowResize.resizing) {
259+
this.table.scenegraph.component.hideResizeRow();
260+
this.rowResize.resizing = false;
261+
}
262+
if (this.interactionState === InteractionState.grabing) {
263+
this.interactionState = InteractionState.default;
264+
}
265+
}
253266
_updateOptionSetState() {
267+
this.endResizeIfResizing();
254268
this.interactionState = InteractionState.default;
255269
// this.select = {
256270
// highlightScope: HighlightScope.single,

0 commit comments

Comments
 (0)