This commit is contained in:
2025-09-02 17:10:00 +08:00
parent 981d93d28f
commit 888cca65e1
3 changed files with 55 additions and 43 deletions

View File

@@ -65,8 +65,8 @@ export function useDesktopInit(containerStr: string) {
const oldAppIcon = oldAppIcons.find(oldAppIcon => oldAppIcon.name === processInfo.name) const oldAppIcon = oldAppIcons.find(oldAppIcon => oldAppIcon.name === processInfo.name)
// 左上角坐标原点,从上到下从左到右 索引从1开始 // 左上角坐标原点,从上到下从左到右 索引从1开始
const x = Math.floor(index / gridTemplate.rowCount) + 1 const x = index % gridTemplate.rowCount + 1
const y = index % gridTemplate.rowCount + 1 const y = Math.floor(index / gridTemplate.rowCount) + 1
return { return {
name: processInfo.name, name: processInfo.name,

View File

@@ -1,8 +1,12 @@
/** 拖拽移动开始的回调 */
type TDragStartCallback = (x: number, y: number) => void; type TDragStartCallback = (x: number, y: number) => void;
/** 拖拽移动中的回调 */
type TDragMoveCallback = (x: number, y: number) => void; type TDragMoveCallback = (x: number, y: number) => void;
/** 拖拽移动结束的回调 */
type TDragEndCallback = (x: number, y: number) => void; type TDragEndCallback = (x: number, y: number) => void;
type ResizeDirection = /** 拖拽调整尺寸的方向 */
type TResizeDirection =
| 'top' | 'top'
| 'bottom' | 'bottom'
| 'left' | 'left'
@@ -12,12 +16,18 @@ type ResizeDirection =
| 'bottom-left' | 'bottom-left'
| 'bottom-right'; | 'bottom-right';
interface ResizeCallbackData { /** 拖拽调整尺寸回调数据 */
interface IResizeCallbackData {
/** 宽度 */
width: number; width: number;
/** 高度 */
height: number; height: number;
/** 顶点坐标 */
top: number; top: number;
/** 底点坐标 */
left: number; left: number;
direction: ResizeDirection; /** 拖拽调整尺寸的方向 */
direction: TResizeDirection;
} }
/** 拖拽参数 */ /** 拖拽参数 */
@@ -41,28 +51,38 @@ interface IDraggableOptions {
/** 是否允许超出边界 */ /** 是否允许超出边界 */
allowOverflow?: boolean; allowOverflow?: boolean;
/** 拖拽回调 */ /** 拖拽开始回调 */
onStart?: TDragStartCallback; onStart?: TDragStartCallback;
/** 拖拽移动中的回调 */
onMove?: TDragMoveCallback; onMove?: TDragMoveCallback;
/** 拖拽结束回调 */
onEnd?: TDragEndCallback; onEnd?: TDragEndCallback;
/** 调整尺寸最小最大值 */ /** 调整尺寸最小宽度 */
minWidth?: number; minWidth?: number;
/** 调整尺寸的最小高度 */
minHeight?: number; minHeight?: number;
/** 调整尺寸的最大宽度 */
maxWidth?: number; maxWidth?: number;
/** 调整尺寸的最大高度 */
maxHeight?: number; maxHeight?: number;
/** 调整尺寸回调 */ /** 拖拽调整尺寸回调 */
onResize?: (data: ResizeCallbackData) => void; onResize?: (data: IResizeCallbackData) => void;
onResizeEnd?: (data: ResizeCallbackData) => void; /** 拖拽调整尺寸结束回调 */
onResizeEnd?: (data: IResizeCallbackData) => void;
} }
/** 拖拽范围边界 */ /** 拖拽范围边界 */
interface IBoundaryRect { interface IBoundaryRect {
minX?: number; /** 最小 X 坐标 */
maxX?: number; minX?: number;
minY?: number; /** 最大 X 坐标 */
maxY?: number; maxX?: number;
/** 最小 Y 坐标 */
minY?: number;
/** 最大 Y 坐标 */
maxY?: number;
} }
/** /**
@@ -70,6 +90,7 @@ interface IBoundaryRect {
*/ */
export class DraggableResizable { export class DraggableResizable {
// ---------------- Drag 属性 ---------------- // ---------------- Drag 属性 ----------------
private handle?: HTMLElement; private handle?: HTMLElement;
private target: HTMLElement; private target: HTMLElement;
private boundary?: HTMLElement | IBoundaryRect; private boundary?: HTMLElement | IBoundaryRect;
@@ -99,7 +120,8 @@ export class DraggableResizable {
private animationFrame?: number; private animationFrame?: number;
// ---------------- Resize 属性 ---------------- // ---------------- Resize 属性 ----------------
private currentDirection: ResizeDirection | null = null;
private currentDirection: TResizeDirection | null = null;
private startWidth = 0; private startWidth = 0;
private startHeight = 0; private startHeight = 0;
private startTop = 0; private startTop = 0;
@@ -108,8 +130,8 @@ export class DraggableResizable {
private minHeight: number; private minHeight: number;
private maxWidth: number; private maxWidth: number;
private maxHeight: number; private maxHeight: number;
private onResize?: (data: ResizeCallbackData) => void; private onResize?: (data: IResizeCallbackData) => void;
private onResizeEnd?: (data: ResizeCallbackData) => void; private onResizeEnd?: (data: IResizeCallbackData) => void;
constructor(options: IDraggableOptions) { constructor(options: IDraggableOptions) {
// Drag // Drag
@@ -148,9 +170,8 @@ export class DraggableResizable {
private init() { private init() {
if (this.handle) { if (this.handle) {
this.handle.addEventListener('mousedown', this.onMouseDown); this.handle.addEventListener('mousedown', this.onMouseDown);
} else {
this.target.addEventListener('mousedown', this.onMouseDown);
} }
this.target.addEventListener('mousedown', this.onMouseDown);
this.target.addEventListener('mousemove', this.onMouseMoveCursor); this.target.addEventListener('mousemove', this.onMouseMoveCursor);
this.target.addEventListener('mouseleave', this.onMouseLeave); this.target.addEventListener('mouseleave', this.onMouseLeave);
@@ -164,7 +185,6 @@ export class DraggableResizable {
} }
} }
// ---------------- Drag 方法 ----------------
private onMouseDown = (e: MouseEvent) => { private onMouseDown = (e: MouseEvent) => {
const dir = this.getResizeDirection(e); const dir = this.getResizeDirection(e);
if (dir) { if (dir) {
@@ -359,8 +379,7 @@ export class DraggableResizable {
this.containerRect = element.getBoundingClientRect(); this.containerRect = element.getBoundingClientRect();
} }
// ---------------- Resize 方法 ---------------- private getResizeDirection(e: MouseEvent): TResizeDirection | null {
private getResizeDirection(e: MouseEvent): ResizeDirection | null {
const rect = this.target.getBoundingClientRect(); const rect = this.target.getBoundingClientRect();
const offset = 8; const offset = 8;
const x = e.clientX; const x = e.clientX;
@@ -370,6 +389,7 @@ export class DraggableResizable {
const bottom = y >= rect.bottom - offset && y <= rect.bottom; const bottom = y >= rect.bottom - offset && y <= rect.bottom;
const left = x >= rect.left && x <= rect.left + offset; const left = x >= rect.left && x <= rect.left + offset;
const right = x >= rect.right - offset && x <= rect.right; const right = x >= rect.right - offset && x <= rect.right;
// console.log('resize', top, bottom, left, right)
if (top && left) return 'top-left'; if (top && left) return 'top-left';
if (top && right) return 'top-right'; if (top && right) return 'top-right';
@@ -383,12 +403,12 @@ export class DraggableResizable {
return null; return null;
} }
private updateCursor(direction: ResizeDirection | null) { private updateCursor(direction: TResizeDirection | null) {
if (!direction) { if (!direction) {
this.target.style.cursor = 'default'; this.target.style.cursor = 'default';
return; return;
} }
const cursorMap: Record<ResizeDirection, string> = { const cursorMap: Record<TResizeDirection, string> = {
top: 'ns-resize', top: 'ns-resize',
bottom: 'ns-resize', bottom: 'ns-resize',
left: 'ew-resize', left: 'ew-resize',
@@ -411,7 +431,7 @@ export class DraggableResizable {
if (!this.currentDirection && !this.isDragging) this.updateCursor(null); if (!this.currentDirection && !this.isDragging) this.updateCursor(null);
}; };
private startResize(e: MouseEvent, dir: ResizeDirection) { private startResize(e: MouseEvent, dir: TResizeDirection) {
this.currentDirection = dir; this.currentDirection = dir;
const rect = this.target.getBoundingClientRect(); const rect = this.target.getBoundingClientRect();
this.startX = e.clientX; this.startX = e.clientX;

View File

@@ -48,28 +48,20 @@ export default class WindowFormImpl implements IWindowForm {
dom.style.height = `${this.height}px`; dom.style.height = `${this.height}px`;
dom.style.zIndex = '100'; dom.style.zIndex = '100';
dom.style.backgroundColor = 'white'; dom.style.backgroundColor = 'white';
// new Draggable( { const div = document.createElement('div');
// handle: dom, div.style.width = '100%';
// target: dom, div.style.height = '20px';
// mode: 'position', div.style.backgroundColor = 'red';
// snapThreshold: 20, dom.appendChild(div)
// boundary: document.body
// })
// new Resizable({
// target: dom,
// onResizeEnd: (data) => {
// console.log(data)
// }
// })
new DraggableResizable({ new DraggableResizable({
target: dom, target: dom,
handle: dom, handle: div,
mode: 'position', mode: 'position',
snapThreshold: 20, snapThreshold: 20,
boundary: document.body boundary: document.body,
}) })
this.desktopRootDom.appendChild(dom); this.desktopRootDom.appendChild(dom);
} }
} }