+
+
+ {{ state }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
index 579dd5247..f48c54d50 100644
--- a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
+++ b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
@@ -489,6 +489,7 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const { vue: options, width, height, visible, display, ...rest } = attribute || {};
const { x: left, y: top } = this.calculatePosition(graphic, options.anchorType);
const { left: offsetX, top: offsetTop } = this.calculateOffset(stage, nativeContainer, left, top);
+ const { safeWidth, safeHeight } = this.getScrollbarSafeSize(graphic, offsetX, offsetTop, width, height, options);
const { id } = this.getGraphicOptions(graphic) || {};
const record = id ? this.htmlMap[id] : null;
@@ -499,10 +500,6 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
// 位置变化检查
const positionChanged =
!record.lastPosition || record.lastPosition.x !== offsetX || record.lastPosition.y !== offsetTop;
- if (!positionChanged) {
- // 位置没有变化,无需更新样式
- return;
- }
// 默认自定义区域内也可带动表格画布滚动
const { pointerEvents } = options;
@@ -510,8 +507,8 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
// 单元格样式
const style = this.convertCellStyle(graphic);
Object.assign(calculateStyle, {
- width: `${width}px`,
- height: `${height}px`,
+ width: `${safeWidth}px`,
+ height: `${safeHeight}px`,
overflow: 'hidden',
...(style || {}),
...(rest || {}),
@@ -546,6 +543,38 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
record.lastStyle = calculateStyle;
}
+ record.lastPosition = positionChanged ? { x: offsetX, y: offsetTop } : record.lastPosition;
+ }
+
+ private getScrollbarSafeSize(
+ graphic: IGraphic,
+ offsetX: number,
+ offsetTop: number,
+ width: number,
+ height: number,
+ options: any
+ ) {
+ const pointerEvents = options?.pointerEvents === true ? 'all' : options?.pointerEvents || 'none';
+ const table = getTargetGroup(graphic)?.stage?.table;
+ const scrollStyle = table?.theme?.scrollStyle;
+ const barToSide = scrollStyle?.barToSide ?? false;
+ let safeWidth = width;
+ let safeHeight = height;
+
+ if (pointerEvents !== 'none' && table && !barToSide) {
+ const verticalVisible = scrollStyle?.verticalVisible ?? scrollStyle?.visible;
+ const horizontalVisible = scrollStyle?.horizontalVisible ?? scrollStyle?.visible;
+ const hasVerticalScrollBar = verticalVisible !== 'none' && table.getAllRowsHeight() > table.tableNoFrameHeight;
+ const hasHorizontalScrollBar = horizontalVisible !== 'none' && table.getAllColsWidth() > table.tableNoFrameWidth;
+ const scrollBarSize = scrollStyle?.width ?? 7;
+ const maxRight = table.tableNoFrameWidth - (hasVerticalScrollBar ? scrollBarSize : 0);
+ const maxBottom = table.tableNoFrameHeight - (hasHorizontalScrollBar ? scrollBarSize : 0);
+
+ safeWidth = Math.max(0, Math.min(width, maxRight - offsetX));
+ safeHeight = Math.max(0, Math.min(height, maxBottom - offsetTop));
+ }
+
+ return { safeWidth, safeHeight };
}
/**
From bc032ed9f356f35b9e111ff6142719109839747a Mon Sep 17 00:00:00 2001
From: fangsmile <892739385@qq.com>
Date: Wed, 29 Jul 2026 10:57:53 +0800
Subject: [PATCH 2/7] fix(vue-vtable): clip custom layout by scrollbar bounds
---
.../custom/vtable-vue-attribute-plugin.ts | 49 +++++++++++++++++--
1 file changed, 45 insertions(+), 4 deletions(-)
diff --git a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
index f48c54d50..d2d8e6eb0 100644
--- a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
+++ b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
@@ -567,11 +567,52 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const hasVerticalScrollBar = verticalVisible !== 'none' && table.getAllRowsHeight() > table.tableNoFrameHeight;
const hasHorizontalScrollBar = horizontalVisible !== 'none' && table.getAllColsWidth() > table.tableNoFrameWidth;
const scrollBarSize = scrollStyle?.width ?? 7;
- const maxRight = table.tableNoFrameWidth - (hasVerticalScrollBar ? scrollBarSize : 0);
- const maxBottom = table.tableNoFrameHeight - (hasHorizontalScrollBar ? scrollBarSize : 0);
+ const groupX = table.scenegraph?.tableGroup?.attribute?.x ?? 0;
+ const groupY = table.scenegraph?.tableGroup?.attribute?.y ?? 0;
+ const hoverOn = scrollStyle?.hoverOn;
+ const domRight = offsetX + width;
+ const domBottom = offsetTop + height;
+
+ if (hasVerticalScrollBar) {
+ const verticalLeft =
+ Math.min(table.tableNoFrameWidth, table.getAllColsWidth()) - (hoverOn ? scrollBarSize : -groupX);
+ const verticalTop = table.getFrozenRowsHeight() + (!hoverOn ? groupY : 0);
+ const verticalBottom =
+ verticalTop + table.tableNoFrameHeight - table.getFrozenRowsHeight() - table.getBottomFrozenRowsHeight();
+
+ if (
+ offsetTop < verticalBottom &&
+ domBottom > verticalTop &&
+ offsetX < verticalLeft + scrollBarSize &&
+ domRight > verticalLeft
+ ) {
+ safeWidth = Math.max(0, Math.min(width, verticalLeft - offsetX));
+ }
+ }
- safeWidth = Math.max(0, Math.min(width, maxRight - offsetX));
- safeHeight = Math.max(0, Math.min(height, maxBottom - offsetTop));
+ if (hasHorizontalScrollBar) {
+ const ignoreFrozenCols = scrollStyle?.ignoreFrozenCols ?? false;
+ const horizontalLeft = ignoreFrozenCols
+ ? !hoverOn
+ ? groupX
+ : 0
+ : table.getFrozenColsWidth() + (!hoverOn ? groupX : 0);
+ const horizontalWidth = ignoreFrozenCols
+ ? table.tableNoFrameWidth
+ : table.tableNoFrameWidth - table.getFrozenColsWidth() - table.getRightFrozenColsWidth();
+ const horizontalTop =
+ Math.min(table.tableNoFrameHeight, table.getAllRowsHeight()) - (hoverOn ? scrollBarSize : -groupY);
+ const horizontalRight = horizontalLeft + horizontalWidth;
+
+ if (
+ offsetX < horizontalRight &&
+ domRight > horizontalLeft &&
+ offsetTop < horizontalTop + scrollBarSize &&
+ domBottom > horizontalTop
+ ) {
+ safeHeight = Math.max(0, Math.min(height, horizontalTop - offsetTop));
+ }
+ }
}
return { safeWidth, safeHeight };
From 828cb661c2f4eca5867cc97ac90572f206c52325 Mon Sep 17 00:00:00 2001
From: fangsmile <892739385@qq.com>
Date: Wed, 29 Jul 2026 11:11:07 +0800
Subject: [PATCH 3/7] fix(vue-vtable): align scrollbar clip coordinates
---
.../custom/vtable-vue-attribute-plugin.ts | 47 ++++++++++++++-----
1 file changed, 36 insertions(+), 11 deletions(-)
diff --git a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
index d2d8e6eb0..6de5c7cd6 100644
--- a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
+++ b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
@@ -489,7 +489,16 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const { vue: options, width, height, visible, display, ...rest } = attribute || {};
const { x: left, y: top } = this.calculatePosition(graphic, options.anchorType);
const { left: offsetX, top: offsetTop } = this.calculateOffset(stage, nativeContainer, left, top);
- const { safeWidth, safeHeight } = this.getScrollbarSafeSize(graphic, offsetX, offsetTop, width, height, options);
+ const { safeWidth, safeHeight } = this.getScrollbarSafeSize(
+ graphic,
+ stage,
+ nativeContainer,
+ offsetX,
+ offsetTop,
+ width,
+ height,
+ options
+ );
const { id } = this.getGraphicOptions(graphic) || {};
const record = id ? this.htmlMap[id] : null;
@@ -548,6 +557,8 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
private getScrollbarSafeSize(
graphic: IGraphic,
+ stage: IStage,
+ nativeContainer: HTMLElement,
offsetX: number,
offsetTop: number,
width: number,
@@ -579,14 +590,21 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const verticalTop = table.getFrozenRowsHeight() + (!hoverOn ? groupY : 0);
const verticalBottom =
verticalTop + table.tableNoFrameHeight - table.getFrozenRowsHeight() - table.getBottomFrozenRowsHeight();
+ const { left: verticalDomLeft, top: verticalDomTop } = this.calculateOffset(
+ stage,
+ nativeContainer,
+ verticalLeft,
+ verticalTop
+ );
+ const verticalDomBottom = verticalDomTop + verticalBottom - verticalTop;
if (
- offsetTop < verticalBottom &&
- domBottom > verticalTop &&
- offsetX < verticalLeft + scrollBarSize &&
- domRight > verticalLeft
+ offsetTop < verticalDomBottom &&
+ domBottom > verticalDomTop &&
+ offsetX < verticalDomLeft + scrollBarSize &&
+ domRight > verticalDomLeft
) {
- safeWidth = Math.max(0, Math.min(width, verticalLeft - offsetX));
+ safeWidth = Math.max(0, Math.min(width, verticalDomLeft - offsetX));
}
}
@@ -603,14 +621,21 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const horizontalTop =
Math.min(table.tableNoFrameHeight, table.getAllRowsHeight()) - (hoverOn ? scrollBarSize : -groupY);
const horizontalRight = horizontalLeft + horizontalWidth;
+ const { left: horizontalDomLeft, top: horizontalDomTop } = this.calculateOffset(
+ stage,
+ nativeContainer,
+ horizontalLeft,
+ horizontalTop
+ );
+ const horizontalDomRight = horizontalDomLeft + horizontalRight - horizontalLeft;
if (
- offsetX < horizontalRight &&
- domRight > horizontalLeft &&
- offsetTop < horizontalTop + scrollBarSize &&
- domBottom > horizontalTop
+ offsetX < horizontalDomRight &&
+ domRight > horizontalDomLeft &&
+ offsetTop < horizontalDomTop + scrollBarSize &&
+ domBottom > horizontalDomTop
) {
- safeHeight = Math.max(0, Math.min(height, horizontalTop - offsetTop));
+ safeHeight = Math.max(0, Math.min(height, horizontalDomTop - offsetTop));
}
}
}
From 1eb4d2891dd584ee2f6d24124e7f6033547a9514 Mon Sep 17 00:00:00 2001
From: fangsmile <892739385@qq.com>
Date: Wed, 29 Jul 2026 12:48:03 +0800
Subject: [PATCH 4/7] fix(vue-vtable): match horizontal scrollbar range
---
.../custom/vtable-vue-attribute-plugin.ts | 19 ++++++++++++++++++-
1 file changed, 18 insertions(+), 1 deletion(-)
diff --git a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
index 6de5c7cd6..15d2cdd0f 100644
--- a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
+++ b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
@@ -576,7 +576,8 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
const verticalVisible = scrollStyle?.verticalVisible ?? scrollStyle?.visible;
const horizontalVisible = scrollStyle?.horizontalVisible ?? scrollStyle?.visible;
const hasVerticalScrollBar = verticalVisible !== 'none' && table.getAllRowsHeight() > table.tableNoFrameHeight;
- const hasHorizontalScrollBar = horizontalVisible !== 'none' && table.getAllColsWidth() > table.tableNoFrameWidth;
+ const hasHorizontalScrollBar =
+ horizontalVisible !== 'none' && this.getBodyHorizontalScrollRange(table) > this.getScrollSizeTolerance(table);
const scrollBarSize = scrollStyle?.width ?? 7;
const groupX = table.scenegraph?.tableGroup?.attribute?.x ?? 0;
const groupY = table.scenegraph?.tableGroup?.attribute?.y ?? 0;
@@ -643,6 +644,22 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
return { safeWidth, safeHeight };
}
+ private getBodyHorizontalScrollRange(table: any) {
+ const totalWidth = table.getAllColsWidth();
+ const frozenColsWidth = table.getFrozenColsWidth();
+ const rightFrozenColsWidth = table.getRightFrozenColsWidth();
+ const frozenColsContentWidth = table.getFrozenColsContentWidth?.() ?? frozenColsWidth;
+ const rightFrozenColsContentWidth = table.getRightFrozenColsContentWidth?.() ?? rightFrozenColsWidth;
+ const bodyViewportWidth = table.tableNoFrameWidth - frozenColsWidth - rightFrozenColsWidth;
+ const bodyContentWidth = totalWidth - frozenColsContentWidth - rightFrozenColsContentWidth;
+
+ return Math.max(0, bodyContentWidth - bodyViewportWidth);
+ }
+
+ private getScrollSizeTolerance(table: any) {
+ return table.options?.customConfig?._disableColumnAndRowSizeRound ? 1 : 0;
+ }
+
/**
* @description: 事件监听器管理
* @param {HTMLElement} wrapContainer
From 2d21bb1fc391d6026b7b38a0251ab79cb5fe2d77 Mon Sep 17 00:00:00 2001
From: fangsmile <892739385@qq.com>
Date: Wed, 29 Jul 2026 14:06:45 +0800
Subject: [PATCH 5/7] fix(vue-vtable): align vertical scrollbar tolerance
---
.../src/components/custom/vtable-vue-attribute-plugin.ts | 6 ++++--
1 file changed, 4 insertions(+), 2 deletions(-)
diff --git a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
index 15d2cdd0f..791698aec 100644
--- a/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
+++ b/packages/vue-vtable/src/components/custom/vtable-vue-attribute-plugin.ts
@@ -575,9 +575,11 @@ export class VTableVueAttributePlugin extends HtmlAttributePlugin implements IPl
if (pointerEvents !== 'none' && table && !barToSide) {
const verticalVisible = scrollStyle?.verticalVisible ?? scrollStyle?.visible;
const horizontalVisible = scrollStyle?.horizontalVisible ?? scrollStyle?.visible;
- const hasVerticalScrollBar = verticalVisible !== 'none' && table.getAllRowsHeight() > table.tableNoFrameHeight;
+ const sizeTolerance = this.getScrollSizeTolerance(table);
+ const hasVerticalScrollBar =
+ verticalVisible !== 'none' && table.getAllRowsHeight() > table.tableNoFrameHeight + sizeTolerance;
const hasHorizontalScrollBar =
- horizontalVisible !== 'none' && this.getBodyHorizontalScrollRange(table) > this.getScrollSizeTolerance(table);
+ horizontalVisible !== 'none' && this.getBodyHorizontalScrollRange(table) > sizeTolerance;
const scrollBarSize = scrollStyle?.width ?? 7;
const groupX = table.scenegraph?.tableGroup?.attribute?.x ?? 0;
const groupY = table.scenegraph?.tableGroup?.attribute?.y ?? 0;
From ebd2af57b5c4748295605f9835990d3af7414d4c Mon Sep 17 00:00:00 2001
From: fangsmile <892739385@qq.com>
Date: Wed, 29 Jul 2026 14:24:13 +0800
Subject: [PATCH 6/7] fix(vue-vtable): clip frozen horizontal scrollbars
---
.../Issue5157CustomLayoutScrollbar.vue | 51 ++++++++++++++-----
.../custom/vtable-vue-attribute-plugin.ts | 45 ++++++++++++----
2 files changed, 73 insertions(+), 23 deletions(-)
diff --git a/packages/vue-vtable/demo/src/table/gramatical/composition/Issue5157CustomLayoutScrollbar.vue b/packages/vue-vtable/demo/src/table/gramatical/composition/Issue5157CustomLayoutScrollbar.vue
index baaa7ba7e..ff6302d2a 100644
--- a/packages/vue-vtable/demo/src/table/gramatical/composition/Issue5157CustomLayoutScrollbar.vue
+++ b/packages/vue-vtable/demo/src/table/gramatical/composition/Issue5157CustomLayoutScrollbar.vue
@@ -4,7 +4,19 @@