From 3d402de0af158e919e1a2cb6ceb46196365f74b6 Mon Sep 17 00:00:00 2001 From: azure <983547216@qq.com> Date: Thu, 4 Sep 2025 21:37:04 +0800 Subject: [PATCH] =?UTF-8?q?=E7=AA=97=E4=BD=93=E6=9C=80=E5=A4=A7=E5=8C=96?= =?UTF-8?q?=E3=80=81=E6=9C=80=E5=B0=8F=E5=8C=96=E5=92=8C=E6=81=A2=E5=A4=8D?= =?UTF-8?q?=E9=BB=98=E8=AE=A4=E7=8A=B6=E6=80=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/core/utils/DraggableResizableWindow.ts | 88 ++++++++++++++++++---- 1 file changed, 74 insertions(+), 14 deletions(-) diff --git a/src/core/utils/DraggableResizableWindow.ts b/src/core/utils/DraggableResizableWindow.ts index 5bc8c71..7389d28 100644 --- a/src/core/utils/DraggableResizableWindow.ts +++ b/src/core/utils/DraggableResizableWindow.ts @@ -492,35 +492,95 @@ export class DraggableResizableWindow { this.updateCursor(dir); }; - /** ---------------- 最小化/最大化 ---------------- */ + // 最小化到任务栏 public minimize() { if (this.state === 'minimized') return; this.state = 'minimized'; - const taskbar = document.getElementById(this.taskbarElementId); - if (!taskbar) return; + + const taskbar = document.querySelector(this.taskbarElementId); + if (!taskbar) throw new Error('任务栏元素未找到'); + const rect = taskbar.getBoundingClientRect(); - this.animateTo(rect.left, rect.top, 200); - this.target.style.width = '0px'; - this.target.style.height = '0px'; + const startX = this.currentX; + const startY = this.currentY; + const startW = this.target.offsetWidth; + const startH = this.target.offsetHeight; + + this.animateWindow(startX, startY, startW, startH, rect.left, rect.top, rect.width, rect.height, 400); } + /** 最大化 */ public maximize() { if (this.state === 'maximized') return; this.state = 'maximized'; - const bounds = { top: 0, left: 0, width: window.innerWidth, height: window.innerHeight }; - this.maximizedBounds = bounds; - this.animateTo(bounds.left, bounds.top, 200); - this.target.style.width = `${bounds.width}px`; - this.target.style.height = `${bounds.height}px`; + + const rect = this.target.getBoundingClientRect(); + this.targetDefaultBounds = { width: rect.width, height: rect.height, left: rect.left, top: rect.top }; + + const startX = this.currentX; + const startY = this.currentY; + const startW = rect.width; + const startH = rect.height; + + const targetX = 0; + const targetY = 0; + const targetW = this.containerRect?.width ?? window.innerWidth; + const targetH = this.containerRect?.height ?? window.innerHeight; + + this.animateWindow(startX, startY, startW, startH, targetX, targetY, targetW, targetH, 300); } + /** 恢复到默认窗体状态 */ public restore() { if (this.state === 'default') return; this.state = 'default'; const b = this.targetDefaultBounds; - this.animateTo(b.left, b.top, 200); - this.target.style.width = `${b.width}px`; - this.target.style.height = `${b.height}px`; + + const startX = this.currentX; + const startY = this.currentY; + const startW = this.target.offsetWidth; + const startH = this.target.offsetHeight; + + this.animateWindow(startX, startY, startW, startH, b.left, b.top, b.width, b.height, 300); + } + + private animateWindow( + startX: number, + startY: number, + startW: number, + startH: number, + targetX: number, + targetY: number, + targetW: number, + targetH: number, + duration: number, + onComplete?: () => void + ) { + const startTime = performance.now(); + const step = (now: number) => { + const elapsed = now - startTime; + const progress = Math.min(elapsed / duration, 1); + const ease = 1 - Math.pow(1 - progress, 3); + + const x = startX + (targetX - startX) * ease; + const y = startY + (targetY - startY) * ease; + const w = startW + (targetW - startW) * ease; + const h = startH + (targetH - startH) * ease; + + this.target.style.width = `${w}px`; + this.target.style.height = `${h}px`; + this.applyPosition(x, y, false); + + if (progress < 1) { + requestAnimationFrame(step); + } else { + this.target.style.width = `${targetW}px`; + this.target.style.height = `${targetH}px`; + this.applyPosition(targetX, targetY, true); + onComplete?.(); + } + }; + requestAnimationFrame(step); } private updateDefaultBounds(left: number, top: number, width?: number, height?: number) {