From 67728c5c557212eb1edf6c0ae5b4fb0f970810cc Mon Sep 17 00:00:00 2001 From: Azure <983547216@qq.com> Date: Fri, 12 Sep 2025 12:53:04 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=BB=E8=BE=91=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/utils/DraggableResizableWindow.ts | 75 +++++++++------------- src/core/window/css/window-form.scss | 8 ++- src/core/window/impl/WindowFormImpl.ts | 2 +- 3 files changed, 37 insertions(+), 48 deletions(-) diff --git a/src/core/utils/DraggableResizableWindow.ts b/src/core/utils/DraggableResizableWindow.ts index 91d4d80..9f0436c 100644 --- a/src/core/utils/DraggableResizableWindow.ts +++ b/src/core/utils/DraggableResizableWindow.ts @@ -51,8 +51,8 @@ interface IDraggableResizableOptions { target: HTMLElement; /** 拖拽句柄 */ handle?: HTMLElement; - /** 拖拽边界或容器元素 */ - boundary?: IBoundaryRect | HTMLElement; + /** 拖拽边界容器元素 */ + boundaryElement?: HTMLElement; /** 移动步进(网格吸附) */ snapGrid?: number; /** 关键点吸附阈值 */ @@ -110,7 +110,7 @@ interface IBoundaryRect { export class DraggableResizableWindow { private handle?: HTMLElement; private target: HTMLElement; - private boundary?: HTMLElement | IBoundaryRect; + private boundaryElement: HTMLElement; private snapGrid: number; private snapThreshold: number; private snapAnimation: boolean; @@ -153,7 +153,7 @@ export class DraggableResizableWindow { private maxWidth: number; private maxHeight: number; - private containerRect?: DOMRect; + private containerRect: DOMRect; private resizeObserver?: ResizeObserver; private mutationObserver: MutationObserver; private animationFrame?: number; @@ -174,7 +174,7 @@ export class DraggableResizableWindow { constructor(options: IDraggableResizableOptions) { this.handle = options.handle; this.target = options.target; - this.boundary = options.boundary; + this.boundaryElement = options.boundaryElement ?? document.body; this.snapGrid = options.snapGrid ?? 1; this.snapThreshold = options.snapThreshold ?? 0; this.snapAnimation = options.snapAnimation ?? false; @@ -193,15 +193,6 @@ export class DraggableResizableWindow { this.onResizeEnd = options.onResizeEnd; this.onWindowStateChange = options.onWindowStateChange; - requestAnimationFrame(() => { - this.targetBounds = { - width: this.target.offsetWidth, - height: this.target.offsetHeight, - top: this.target.offsetTop, - left: this.target.offsetLeft, - }; - }); - this.taskbarElementId = options.taskbarElementId; this.target.style.position = "absolute"; @@ -210,6 +201,19 @@ export class DraggableResizableWindow { this.target.style.transform = "translate(0px, 0px)"; this.init(); + + requestAnimationFrame(() => { + this.targetBounds = { + width: this.target.offsetWidth, + height: this.target.offsetHeight, + top: this.target.offsetTop, + left: this.target.offsetLeft, + }; + this.containerRect = this.boundaryElement.getBoundingClientRect(); + const x = this.containerRect.width / 2 - this.target.offsetWidth / 2; + const y = this.containerRect.height / 2 - this.target.offsetHeight / 2; + this.target.style.transform = `translate(${x}px, ${y}px)`; + }); } private init() { @@ -220,7 +224,7 @@ export class DraggableResizableWindow { this.target.addEventListener('mouseleave', this.onMouseLeave); document.addEventListener('mousemove', this.onDocumentMouseMoveCursor); - if (this.boundary instanceof HTMLElement) this.observeResize(this.boundary); + this.observeResize(this.boundaryElement); this.mutationObserver = new MutationObserver(mutations => { for (const mutation of mutations) { @@ -382,19 +386,12 @@ export class DraggableResizableWindow { } private applyBoundary() { - if (!this.boundary || this.allowOverflow) return; + if (this.allowOverflow) return; let { x, y } = { x: this.currentX, y: this.currentY }; - if (this.boundary instanceof HTMLElement && this.containerRect) { - const rect = this.target.getBoundingClientRect(); - x = Math.min(Math.max(x, 0), this.containerRect.width - rect.width); - y = Math.min(Math.max(y, 0), this.containerRect.height - rect.height); - } else if (!(this.boundary instanceof HTMLElement) && this.boundary) { - if (this.boundary.minX !== undefined) x = Math.max(x, this.boundary.minX); - if (this.boundary.maxX !== undefined) x = Math.min(x, this.boundary.maxX); - if (this.boundary.minY !== undefined) y = Math.max(y, this.boundary.minY); - if (this.boundary.maxY !== undefined) y = Math.min(y, this.boundary.maxY); - } + const rect = this.target.getBoundingClientRect(); + x = Math.min(Math.max(x, 0), this.containerRect.width - rect.width); + y = Math.min(Math.max(y, 0), this.containerRect.height - rect.height); this.currentX = x; this.currentY = y; @@ -413,16 +410,9 @@ export class DraggableResizableWindow { private getSnapPoints() { const snapPoints = { x: [] as number[], y: [] as number[] }; - if (this.boundary instanceof HTMLElement && this.containerRect) { - const rect = this.target.getBoundingClientRect(); - snapPoints.x = [0, this.containerRect.width - rect.width]; - snapPoints.y = [0, this.containerRect.height - rect.height]; - } else if (this.boundary && !(this.boundary instanceof HTMLElement)) { - if (this.boundary.minX !== undefined) snapPoints.x.push(this.boundary.minX); - if (this.boundary.maxX !== undefined) snapPoints.x.push(this.boundary.maxX); - if (this.boundary.minY !== undefined) snapPoints.y.push(this.boundary.minY); - if (this.boundary.maxY !== undefined) snapPoints.y.push(this.boundary.maxY); - } + const rect = this.target.getBoundingClientRect(); + snapPoints.x = [0, this.containerRect.width - rect.width]; + snapPoints.y = [0, this.containerRect.height - rect.height]; return snapPoints; } @@ -517,7 +507,7 @@ export class DraggableResizableWindow { newHeight = Math.max(this.minHeight, Math.min(this.maxHeight, newHeight)); // 边界限制 - if (!this.boundary || this.allowOverflow) { + if (this.allowOverflow) { this.currentX = newX; this.currentY = newY; this.target.style.width = `${newWidth}px`; @@ -526,15 +516,8 @@ export class DraggableResizableWindow { return; } - if (this.boundary instanceof HTMLElement && this.containerRect) { - newX = Math.min(Math.max(0, newX), this.containerRect.width - newWidth); - newY = Math.min(Math.max(0, newY), this.containerRect.height - newHeight); - } else if (!(this.boundary instanceof HTMLElement) && this.boundary) { - if (this.boundary.minX !== undefined) newX = Math.max(newX, this.boundary.minX); - if (this.boundary.maxX !== undefined) newX = Math.min(newX, this.boundary.maxX); - if (this.boundary.minY !== undefined) newY = Math.max(newY, this.boundary.minY); - if (this.boundary.maxY !== undefined) newY = Math.min(newY, this.boundary.maxY); - } + newX = Math.min(Math.max(0, newX), this.containerRect.width - newWidth); + newY = Math.min(Math.max(0, newY), this.containerRect.height - newHeight); this.currentX = newX; this.currentY = newY; diff --git a/src/core/window/css/window-form.scss b/src/core/window/css/window-form.scss index f2bd6be..da91e17 100644 --- a/src/core/window/css/window-form.scss +++ b/src/core/window/css/window-form.scss @@ -1,3 +1,5 @@ +$titleBarHeight: 40px; + /* 窗体容器 */ .window { width: 100%; @@ -15,6 +17,8 @@ justify-content: space-between; align-items: center; user-select: none; + width: 100%; + height: $titleBarHeight; .title { display: block; @@ -24,6 +28,7 @@ white-space: nowrap; text-overflow: ellipsis; font-size: 18px; + line-height: $titleBarHeight; } .window-controls { @@ -52,6 +57,7 @@ /* 窗体内容 */ .window-content { - padding: 15px; + width: 100%; + height: calc(100% - #{$titleBarHeight}); background-color: #e0e0e0; } \ No newline at end of file diff --git a/src/core/window/impl/WindowFormImpl.ts b/src/core/window/impl/WindowFormImpl.ts index 28bbfff..8925b15 100644 --- a/src/core/window/impl/WindowFormImpl.ts +++ b/src/core/window/impl/WindowFormImpl.ts @@ -53,7 +53,7 @@ export default class WindowFormImpl implements IWindowForm { handle: header, snapAnimation: true, snapThreshold: 20, - boundary: document.body, + boundaryElement: document.body, taskbarElementId: '#taskbar', onWindowStateChange: (state) => { if (state === 'maximized') {