逻辑修改

This commit is contained in:
2025-09-12 12:53:04 +08:00
parent 27b70ac35f
commit 67728c5c55
3 changed files with 37 additions and 48 deletions

View File

@@ -51,8 +51,8 @@ interface IDraggableResizableOptions {
target: HTMLElement; target: HTMLElement;
/** 拖拽句柄 */ /** 拖拽句柄 */
handle?: HTMLElement; handle?: HTMLElement;
/** 拖拽边界容器元素 */ /** 拖拽边界容器元素 */
boundary?: IBoundaryRect | HTMLElement; boundaryElement?: HTMLElement;
/** 移动步进(网格吸附) */ /** 移动步进(网格吸附) */
snapGrid?: number; snapGrid?: number;
/** 关键点吸附阈值 */ /** 关键点吸附阈值 */
@@ -110,7 +110,7 @@ interface IBoundaryRect {
export class DraggableResizableWindow { export class DraggableResizableWindow {
private handle?: HTMLElement; private handle?: HTMLElement;
private target: HTMLElement; private target: HTMLElement;
private boundary?: HTMLElement | IBoundaryRect; private boundaryElement: HTMLElement;
private snapGrid: number; private snapGrid: number;
private snapThreshold: number; private snapThreshold: number;
private snapAnimation: boolean; private snapAnimation: boolean;
@@ -153,7 +153,7 @@ export class DraggableResizableWindow {
private maxWidth: number; private maxWidth: number;
private maxHeight: number; private maxHeight: number;
private containerRect?: DOMRect; private containerRect: DOMRect;
private resizeObserver?: ResizeObserver; private resizeObserver?: ResizeObserver;
private mutationObserver: MutationObserver; private mutationObserver: MutationObserver;
private animationFrame?: number; private animationFrame?: number;
@@ -174,7 +174,7 @@ export class DraggableResizableWindow {
constructor(options: IDraggableResizableOptions) { constructor(options: IDraggableResizableOptions) {
this.handle = options.handle; this.handle = options.handle;
this.target = options.target; this.target = options.target;
this.boundary = options.boundary; this.boundaryElement = options.boundaryElement ?? document.body;
this.snapGrid = options.snapGrid ?? 1; this.snapGrid = options.snapGrid ?? 1;
this.snapThreshold = options.snapThreshold ?? 0; this.snapThreshold = options.snapThreshold ?? 0;
this.snapAnimation = options.snapAnimation ?? false; this.snapAnimation = options.snapAnimation ?? false;
@@ -193,15 +193,6 @@ export class DraggableResizableWindow {
this.onResizeEnd = options.onResizeEnd; this.onResizeEnd = options.onResizeEnd;
this.onWindowStateChange = options.onWindowStateChange; 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.taskbarElementId = options.taskbarElementId;
this.target.style.position = "absolute"; this.target.style.position = "absolute";
@@ -210,6 +201,19 @@ export class DraggableResizableWindow {
this.target.style.transform = "translate(0px, 0px)"; this.target.style.transform = "translate(0px, 0px)";
this.init(); 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() { private init() {
@@ -220,7 +224,7 @@ export class DraggableResizableWindow {
this.target.addEventListener('mouseleave', this.onMouseLeave); this.target.addEventListener('mouseleave', this.onMouseLeave);
document.addEventListener('mousemove', this.onDocumentMouseMoveCursor); document.addEventListener('mousemove', this.onDocumentMouseMoveCursor);
if (this.boundary instanceof HTMLElement) this.observeResize(this.boundary); this.observeResize(this.boundaryElement);
this.mutationObserver = new MutationObserver(mutations => { this.mutationObserver = new MutationObserver(mutations => {
for (const mutation of mutations) { for (const mutation of mutations) {
@@ -382,19 +386,12 @@ export class DraggableResizableWindow {
} }
private applyBoundary() { private applyBoundary() {
if (!this.boundary || this.allowOverflow) return; if (this.allowOverflow) return;
let { x, y } = { x: this.currentX, y: this.currentY }; let { x, y } = { x: this.currentX, y: this.currentY };
if (this.boundary instanceof HTMLElement && this.containerRect) { const rect = this.target.getBoundingClientRect();
const rect = this.target.getBoundingClientRect(); x = Math.min(Math.max(x, 0), this.containerRect.width - rect.width);
x = Math.min(Math.max(x, 0), this.containerRect.width - rect.width); y = Math.min(Math.max(y, 0), this.containerRect.height - rect.height);
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);
}
this.currentX = x; this.currentX = x;
this.currentY = y; this.currentY = y;
@@ -413,16 +410,9 @@ export class DraggableResizableWindow {
private getSnapPoints() { private getSnapPoints() {
const snapPoints = { x: [] as number[], y: [] as number[] }; const snapPoints = { x: [] as number[], y: [] as number[] };
if (this.boundary instanceof HTMLElement && this.containerRect) { const rect = this.target.getBoundingClientRect();
const rect = this.target.getBoundingClientRect(); snapPoints.x = [0, this.containerRect.width - rect.width];
snapPoints.x = [0, this.containerRect.width - rect.width]; snapPoints.y = [0, this.containerRect.height - rect.height];
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);
}
return snapPoints; return snapPoints;
} }
@@ -517,7 +507,7 @@ export class DraggableResizableWindow {
newHeight = Math.max(this.minHeight, Math.min(this.maxHeight, newHeight)); newHeight = Math.max(this.minHeight, Math.min(this.maxHeight, newHeight));
// 边界限制 // 边界限制
if (!this.boundary || this.allowOverflow) { if (this.allowOverflow) {
this.currentX = newX; this.currentX = newX;
this.currentY = newY; this.currentY = newY;
this.target.style.width = `${newWidth}px`; this.target.style.width = `${newWidth}px`;
@@ -526,15 +516,8 @@ export class DraggableResizableWindow {
return; return;
} }
if (this.boundary instanceof HTMLElement && this.containerRect) { newX = Math.min(Math.max(0, newX), this.containerRect.width - newWidth);
newX = Math.min(Math.max(0, newX), this.containerRect.width - newWidth); newY = Math.min(Math.max(0, newY), this.containerRect.height - newHeight);
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);
}
this.currentX = newX; this.currentX = newX;
this.currentY = newY; this.currentY = newY;

View File

@@ -1,3 +1,5 @@
$titleBarHeight: 40px;
/* 窗体容器 */ /* 窗体容器 */
.window { .window {
width: 100%; width: 100%;
@@ -15,6 +17,8 @@
justify-content: space-between; justify-content: space-between;
align-items: center; align-items: center;
user-select: none; user-select: none;
width: 100%;
height: $titleBarHeight;
.title { .title {
display: block; display: block;
@@ -24,6 +28,7 @@
white-space: nowrap; white-space: nowrap;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: 18px; font-size: 18px;
line-height: $titleBarHeight;
} }
.window-controls { .window-controls {
@@ -52,6 +57,7 @@
/* 窗体内容 */ /* 窗体内容 */
.window-content { .window-content {
padding: 15px; width: 100%;
height: calc(100% - #{$titleBarHeight});
background-color: #e0e0e0; background-color: #e0e0e0;
} }

View File

@@ -53,7 +53,7 @@ export default class WindowFormImpl implements IWindowForm {
handle: header, handle: header,
snapAnimation: true, snapAnimation: true,
snapThreshold: 20, snapThreshold: 20,
boundary: document.body, boundaryElement: document.body,
taskbarElementId: '#taskbar', taskbarElementId: '#taskbar',
onWindowStateChange: (state) => { onWindowStateChange: (state) => {
if (state === 'maximized') { if (state === 'maximized') {