This commit is contained in:
2025-09-12 14:45:32 +08:00
parent 67728c5c55
commit 3401c8b737
4 changed files with 45 additions and 30 deletions

View File

@@ -1,3 +1,5 @@
import type { TWindowFormState } from '@/core/window/types/WindowFormTypes.ts'
/** 拖拽移动开始的回调 */
type TDragStartCallback = (x: number, y: number) => void;
/** 拖拽移动中的回调 */
@@ -16,9 +18,6 @@ type TResizeDirection =
| 'bottom-left'
| 'bottom-right';
/** 窗口状态 */
type TWindowState = 'default' | 'minimized' | 'maximized';
/** 元素边界 */
interface IElementRect {
/** 宽度 */
@@ -88,7 +87,7 @@ interface IDraggableResizableOptions {
onResizeEnd?: (data: IResizeCallbackData) => void;
/** 窗口状态改变回调 */
onWindowStateChange?: (state: TWindowState) => void;
onWindowStateChange?: (state: TWindowFormState) => void;
}
/** 拖拽的范围边界 */
@@ -124,7 +123,7 @@ export class DraggableResizableWindow {
private onResizeMove?: (data: IResizeCallbackData) => void;
private onResizeEnd?: (data: IResizeCallbackData) => void;
private onWindowStateChange?: (state: TWindowState) => void;
private onWindowStateChange?: (state: TWindowFormState) => void;
private isDragging = false;
private currentDirection: TResizeDirection | null = null;
@@ -158,7 +157,7 @@ export class DraggableResizableWindow {
private mutationObserver: MutationObserver;
private animationFrame?: number;
private state: TWindowState = 'default';
private _windowFormState: TWindowFormState = 'default';
/** 元素信息 */
private targetBounds: IElementRect;
/** 最小化前的元素信息 */
@@ -167,8 +166,8 @@ export class DraggableResizableWindow {
private targetPreMaximizedBounds?: IElementRect;
private taskbarElementId: string;
get windowState() {
return this.state;
get windowFormState() {
return this._windowFormState;
}
constructor(options: IDraggableResizableOptions) {
@@ -261,7 +260,7 @@ export class DraggableResizableWindow {
document.removeEventListener('mousemove', this.checkDragStart);
document.removeEventListener('mouseup', this.cancelPendingDrag);
if (this.state === 'maximized') {
if (this._windowFormState === 'maximized') {
const preRect = this.targetPreMaximizedBounds!;
const rect = this.target.getBoundingClientRect();
const relX = e.clientX / rect.width;
@@ -583,9 +582,9 @@ export class DraggableResizableWindow {
// 最小化到任务栏
public minimize() {
if (this.state === 'minimized') return;
if (this._windowFormState === 'minimized') return;
this.targetPreMinimizeBounds = { ...this.targetBounds }
this.state = 'minimized';
this._windowFormState = 'minimized';
const taskbar = document.querySelector(this.taskbarElementId);
if (!taskbar) throw new Error('任务栏元素未找到');
@@ -603,9 +602,9 @@ export class DraggableResizableWindow {
/** 最大化 */
public maximize() {
if (this.state === 'maximized') return;
if (this._windowFormState === 'maximized') return;
this.targetPreMaximizedBounds = { ...this.targetBounds }
this.state = 'maximized';
this._windowFormState = 'maximized';
const rect = this.target.getBoundingClientRect();
@@ -624,19 +623,19 @@ export class DraggableResizableWindow {
/** 恢复到默认窗体状态 */
public restore(onComplete?: () => void) {
if (this.state === 'default') return;
if (this._windowFormState === 'default') return;
let b: IElementRect;
if ((this.state as TWindowState) === 'minimized' && this.targetPreMinimizeBounds) {
if ((this._windowFormState as TWindowFormState) === 'minimized' && this.targetPreMinimizeBounds) {
// 最小化恢复,恢复到最小化前的状态
b = this.targetPreMinimizeBounds;
} else if ((this.state as TWindowState) === 'maximized' && this.targetPreMaximizedBounds) {
} else if ((this._windowFormState as TWindowFormState) === 'maximized' && this.targetPreMaximizedBounds) {
// 最大化恢复,恢复到最大化前的默认状态
b = this.targetPreMaximizedBounds;
} else {
b = this.targetBounds;
}
this.state = 'default';
this._windowFormState = 'default';
this.target.style.display = 'block';
@@ -696,7 +695,7 @@ export class DraggableResizableWindow {
this.target.style.height = `${targetH}px`;
this.applyPosition(targetX, targetY, true);
onComplete?.();
this.onWindowStateChange?.(this.state);
this.onWindowStateChange?.(this._windowFormState);
}
};
requestAnimationFrame(step);

View File

@@ -1,6 +1,15 @@
import type { IProcess } from '@/core/process/IProcess.ts'
import type { TWindowFormState } from '@/core/window/types/WindowFormTypes.ts'
export interface IWindowForm {
/** 窗体id */
get id(): string;
/** 窗体所属的进程 */
get proc(): IProcess | undefined;
/** 窗体元素 */
get windowFormEle(): HTMLElement;
/** 窗体状态 */
get windowFormState(): TWindowFormState;
/** 关闭窗体 */
closeWindowForm(): void;
}

View File

@@ -14,8 +14,8 @@ export default class WindowFormImpl implements IWindowForm {
private dom: HTMLElement;
private drw: DraggableResizableWindow;
private pos: WindowFormPos = { x: 0, y: 0 };
private width: number = 0;
private height: number = 0;
private width: number;
private height: number;
public get id() {
return this._id;
@@ -26,6 +26,12 @@ export default class WindowFormImpl implements IWindowForm {
private get desktopRootDom() {
return XSystem.instance.desktopRootDom;
}
public get windowFormEle() {
return this.dom;
}
public get windowFormState() {
return this.drw.windowFormState
}
constructor(proc: IProcess, config: IWindowFormConfig) {
this._procId = proc.id;
@@ -34,20 +40,21 @@ export default class WindowFormImpl implements IWindowForm {
x: config.left ?? 0,
y: config.top ?? 0
}
this.width = config.width ?? 0;
this.height = config.height ?? 0;
this.width = config.width ?? 200;
this.height = config.height ?? 100;
this.createWindowFrom();
}
private createWindowFrom() {
this.dom = this.windowFormEle();
this.dom = this.createWindowFormEle();
this.dom.style.position = 'absolute';
this.dom.style.width = `${this.width}px`;
this.dom.style.height = `${this.height}px`;
this.dom.style.zIndex = '10';
const header = this.dom.querySelector('.title-bar') as HTMLElement;
const content = this.dom.querySelector('.window-content') as HTMLElement;
this.drw = new DraggableResizableWindow({
target: this.dom,
handle: header,
@@ -67,13 +74,13 @@ export default class WindowFormImpl implements IWindowForm {
this.desktopRootDom.appendChild(this.dom);
}
private closeWindowForm() {
public closeWindowForm() {
this.drw.destroy();
this.desktopRootDom.removeChild(this.dom);
this.proc?.event.notifyEvent('onProcessWindowFormExit', this.id)
}
private windowFormEle() {
private createWindowFormEle() {
const template = document.createElement('template');
template.innerHTML = `
<div class="window">
@@ -85,10 +92,7 @@ export default class WindowFormImpl implements IWindowForm {
<div class="close btn" title="关闭">×</div>
</div>
</div>
<div class="window-content">
<p>这是一个纯静态的 Windows 风格窗体示例。</p>
<p>你可以在这里放置任何内容。</p>
</div>
<div class="window-content"></div>
</div>
`
const fragment = template.content.cloneNode(true) as DocumentFragment;
@@ -99,7 +103,7 @@ export default class WindowFormImpl implements IWindowForm {
windowElement.querySelector('.btn.maximize')
?.addEventListener('click', () => {
if (this.drw.windowState === 'maximized') {
if (this.drw.windowFormState === 'maximized') {
this.drw.restore()
} else {
this.drw.maximize()

View File

@@ -5,3 +5,6 @@ export interface WindowFormPos {
x: number;
y: number;
}
/** 窗口状态 */
export type TWindowFormState = 'default' | 'minimized' | 'maximized';