修改组件逻辑+优化代码
This commit is contained in:
@@ -45,7 +45,7 @@ body {
|
|||||||
background-color: var(--color-light);
|
background-color: var(--color-light);
|
||||||
-webkit-font-smoothing: antialiased; /* 字体抗锯齿 */
|
-webkit-font-smoothing: antialiased; /* 字体抗锯齿 */
|
||||||
text-rendering: optimizeLegibility;
|
text-rendering: optimizeLegibility;
|
||||||
overflow-x: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ===== 排版元素 ===== */
|
/* ===== 排版元素 ===== */
|
||||||
|
|||||||
@@ -42,10 +42,10 @@ interface IElementRect {
|
|||||||
width: number;
|
width: number;
|
||||||
/** 高度 */
|
/** 高度 */
|
||||||
height: number;
|
height: number;
|
||||||
/** 顶点坐标(相对 offsetParent) */
|
/** x坐标 */
|
||||||
top: number;
|
x: number;
|
||||||
/** 左点坐标(相对 offsetParent) */
|
/** y坐标 */
|
||||||
left: number;
|
y: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 窗口自定义事件 */
|
/** 窗口自定义事件 */
|
||||||
@@ -75,38 +75,50 @@ export class WindowFormElement extends LitElement {
|
|||||||
@property({ type: Boolean }) closable = true
|
@property({ type: Boolean }) closable = true
|
||||||
@property({ type: Boolean, reflect: true }) focused: boolean = true
|
@property({ type: Boolean, reflect: true }) focused: boolean = true
|
||||||
@property({ type: String, reflect: true }) windowFormState: TWindowFormState = 'default'
|
@property({ type: String, reflect: true }) windowFormState: TWindowFormState = 'default'
|
||||||
@property({ type: Object }) dragContainer?: HTMLElement
|
@property({ type: Object }) dragContainer?: HTMLElement // 元素的父容器
|
||||||
@property({ type: Boolean }) allowOverflow = true // 允许窗口超出容器
|
@property({ type: Number }) snapDistance = 0 // 吸附距离
|
||||||
@property({ type: Number }) snapDistance = 20 // 吸附距离
|
@property({ type: Boolean }) snapAnimation = false // 吸附动画
|
||||||
@property({ type: Boolean }) snapAnimation = true // 吸附动画
|
|
||||||
@property({ type: Number }) snapAnimationDuration = 300 // 吸附动画时长 ms
|
@property({ type: Number }) snapAnimationDuration = 300 // 吸附动画时长 ms
|
||||||
@property({ type: Number }) maxWidth?: number = Infinity
|
@property({ type: Number }) maxWidth?: number = Infinity
|
||||||
@property({ type: Number }) minWidth?: number = 0
|
@property({ type: Number }) minWidth?: number = 200
|
||||||
@property({ type: Number }) maxHeight?: number = Infinity
|
@property({ type: Number }) maxHeight?: number = Infinity
|
||||||
@property({ type: Number }) minHeight?: number = 0
|
@property({ type: Number }) minHeight?: number = 200
|
||||||
@property({ type: String }) taskbarElementId?: string
|
@property({ type: String }) taskbarElementId?: string
|
||||||
@property({ type: Object }) wfData: any;
|
@property({ type: Object }) wfData: any;
|
||||||
|
|
||||||
private _listeners: Array<{ type: string; original: Function; wrapped: EventListener }> = []
|
private _listeners: Array<{ type: string; original: Function; wrapped: EventListener }> = []
|
||||||
|
|
||||||
// ==== 拖拽/缩放状态(内部变量,不触发渲染) ====
|
// ==== 拖拽/缩放状态(内部变量,不触发渲染) ====
|
||||||
private dragging = false
|
// 自身的x坐标
|
||||||
private resizeDir: TResizeDirection | null = null
|
|
||||||
private startX = 0
|
|
||||||
private startY = 0
|
|
||||||
private startWidth = 0
|
|
||||||
private startHeight = 0
|
|
||||||
private startX_host = 0
|
|
||||||
private startY_host = 0
|
|
||||||
|
|
||||||
private x = 0
|
private x = 0
|
||||||
|
// 自身的y坐标
|
||||||
private y = 0
|
private y = 0
|
||||||
private preX = 0
|
// 自身的宽度
|
||||||
private preY = 0
|
|
||||||
private width = 640
|
private width = 640
|
||||||
|
// 自身的高度
|
||||||
private height = 360
|
private height = 360
|
||||||
|
|
||||||
|
// 记录拖拽开始时自身x坐标
|
||||||
|
private originalX = 0
|
||||||
|
// 记录拖拽开始时自身y坐标
|
||||||
|
private originalY = 0
|
||||||
|
// 鼠标开始拖拽时自身宽度
|
||||||
|
private originalWidth = 640
|
||||||
|
// 鼠标开始拖拽时高度
|
||||||
|
private originalHeight = 360
|
||||||
|
|
||||||
|
// 鼠标开始拖拽时x坐标
|
||||||
|
private pointStartX = 0
|
||||||
|
// 鼠标开始拖拽时x坐标
|
||||||
|
private pointStartY = 0
|
||||||
|
|
||||||
private animationFrame?: number
|
private animationFrame?: number
|
||||||
|
// 是否拖拽状态
|
||||||
|
private dragging = false
|
||||||
|
// 是否缩放状态
|
||||||
private resizing = false
|
private resizing = false
|
||||||
|
// 缩放方向
|
||||||
|
private resizeDir: TResizeDirection | null = null
|
||||||
|
|
||||||
// private get x() {
|
// private get x() {
|
||||||
// return this.wfData.state.x
|
// return this.wfData.state.x
|
||||||
@@ -198,25 +210,28 @@ export class WindowFormElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override firstUpdated() {
|
override firstUpdated() {
|
||||||
console.log(this.wfData)
|
const { width, height } = this.getBoundingClientRect()
|
||||||
// wfem.addEventListener('windowFormFocus', this.windowFormFocusFun)
|
this.width = width || this.width
|
||||||
window.addEventListener('pointerup', this.onPointerUp)
|
this.height = height || this.height
|
||||||
window.addEventListener('pointermove', this.onPointerMove)
|
|
||||||
this.addEventListener('pointerdown', this.toggleFocus)
|
|
||||||
|
|
||||||
const container = this.dragContainer || document.body
|
const container = this.dragContainer || document.body
|
||||||
const containerRect = container.getBoundingClientRect()
|
const containerRect = container.getBoundingClientRect()
|
||||||
this.x = containerRect.width / 2 - this.width / 2
|
this.x = containerRect.width / 2 - this.width / 2
|
||||||
this.y = containerRect.height / 2 - this.height / 2
|
this.y = containerRect.height / 2 - this.height / 2
|
||||||
|
|
||||||
this.style.width = `${this.width}px`
|
this.style.width = `${this.width}px`
|
||||||
this.style.height = `${this.height}px`
|
this.style.height = `${this.height}px`
|
||||||
this.style.transform = `translate(${this.x}px, ${this.y}px)`
|
this.style.transform = `translate(${this.x}px, ${this.y}px)`
|
||||||
|
|
||||||
|
window.addEventListener('pointerup', this.onPointerUp)
|
||||||
|
window.addEventListener('pointermove', this.onPointerMove)
|
||||||
|
this.addEventListener('pointerdown', this.toggleFocus)
|
||||||
|
|
||||||
this.targetBounds = {
|
this.targetBounds = {
|
||||||
width: this.offsetWidth,
|
width: this.width,
|
||||||
height: this.offsetHeight,
|
height: this.height,
|
||||||
top: this.x,
|
x: this.x,
|
||||||
left: this.y,
|
y: this.y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -257,10 +272,10 @@ export class WindowFormElement extends LitElement {
|
|||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|
||||||
this.dragging = true
|
this.dragging = true
|
||||||
this.startX = e.clientX
|
this.pointStartX = e.clientX
|
||||||
this.startY = e.clientY
|
this.pointStartY = e.clientY
|
||||||
this.preX = this.x
|
this.originalX = this.x
|
||||||
this.preY = this.y
|
this.originalY = this.y
|
||||||
this.setPointerCapture?.(e.pointerId)
|
this.setPointerCapture?.(e.pointerId)
|
||||||
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
@@ -272,15 +287,20 @@ export class WindowFormElement extends LitElement {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鼠标指针移动
|
||||||
|
* @param e
|
||||||
|
*/
|
||||||
private onPointerMove = (e: PointerEvent) => {
|
private onPointerMove = (e: PointerEvent) => {
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
const dx = e.clientX - this.startX
|
const dx = e.clientX - this.pointStartX
|
||||||
const dy = e.clientY - this.startY
|
const dy = e.clientY - this.pointStartY
|
||||||
|
|
||||||
const x = this.preX + dx
|
const x = this.originalX + dx
|
||||||
const y = this.preY + dy
|
const y = this.originalY + dy
|
||||||
|
|
||||||
this.applyPosition(x, y, false)
|
const pos = this.applyBoundary(x, y, e.clientX, e.clientY)
|
||||||
|
this.applyPosition(pos.x, pos.y)
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:dragMove', {
|
new CustomEvent('windowForm:dragMove', {
|
||||||
detail: { x, y },
|
detail: { x, y },
|
||||||
@@ -293,6 +313,10 @@ export class WindowFormElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 鼠标指针抬起
|
||||||
|
* @param e
|
||||||
|
*/
|
||||||
private onPointerUp = (e: PointerEvent) => {
|
private onPointerUp = (e: PointerEvent) => {
|
||||||
if (this.dragging) {
|
if (this.dragging) {
|
||||||
this.dragUp(e)
|
this.dragUp(e)
|
||||||
@@ -320,13 +344,14 @@ export class WindowFormElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取最近的吸附点
|
* 根据传入的坐标点位计算吸附距离最近的坐标位置
|
||||||
* @param x 左上角起始点x
|
* @param x 坐标点 x
|
||||||
* @param y 左上角起始点y
|
* @param y 坐标点 y
|
||||||
|
* @returns {x: number, y: number} 新的位置坐标
|
||||||
*/
|
*/
|
||||||
private applySnapping(x: number, y: number) {
|
private calculateSnapping(x: number, y: number): { x: number, y: number} {
|
||||||
let snappedX = x,
|
let snappedX = x
|
||||||
snappedY = y
|
let snappedY = y
|
||||||
const containerSnap = this.getSnapPoints()
|
const containerSnap = this.getSnapPoints()
|
||||||
if (this.snapDistance > 0) {
|
if (this.snapDistance > 0) {
|
||||||
for (const sx of containerSnap.x)
|
for (const sx of containerSnap.x)
|
||||||
@@ -343,22 +368,28 @@ export class WindowFormElement extends LitElement {
|
|||||||
return { x: snappedX, y: snappedY }
|
return { x: snappedX, y: snappedY }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 拖拽结束
|
||||||
|
* @param e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private dragUp(e: PointerEvent) {
|
private dragUp(e: PointerEvent) {
|
||||||
const snapped = this.applySnapping(this.x, this.y)
|
const snapped = this.calculateSnapping(this.x, this.y)
|
||||||
if (this.snapAnimation) {
|
if (this.snapAnimation) {
|
||||||
this.animateTo(snapped.x, snapped.y, this.snapAnimationDuration, () => {
|
this.animateTo(this.x, this.y, snapped.x, snapped.y, this.snapAnimationDuration,
|
||||||
this.updateTargetBounds(snapped.x, snapped.y)
|
(x, y) => {
|
||||||
this.dispatchEvent(
|
this.applyPosition(x, y)
|
||||||
new CustomEvent('windowForm:dragEnd', {
|
},
|
||||||
|
(x, y) => {
|
||||||
|
this.applyPosition(snapped.x, snapped.y)
|
||||||
|
this.dispatchEvent(new CustomEvent('windowForm:dragEnd', {
|
||||||
detail: { x: snapped.x, y: snapped.y },
|
detail: { x: snapped.x, y: snapped.y },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
}),
|
}))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
this.applyPosition(snapped.x, snapped.y, true)
|
this.applyPosition(snapped.x, snapped.y)
|
||||||
this.updateTargetBounds(snapped.x, snapped.y)
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:dragEnd', {
|
new CustomEvent('windowForm:dragEnd', {
|
||||||
detail: { x: snapped.x, y: snapped.y },
|
detail: { x: snapped.x, y: snapped.y },
|
||||||
@@ -369,29 +400,65 @@ export class WindowFormElement extends LitElement {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyPosition(x: number, y: number, isFinal: boolean) {
|
/**
|
||||||
|
* 根据鼠标指针的位置是否在容器边界内来限制窗口坐标
|
||||||
|
* @param x 当前元素的左上角坐标 x
|
||||||
|
* @param y 当前元素的左上角坐标 y
|
||||||
|
* @param pointerX 当前鼠标在容器中的 X 坐标
|
||||||
|
* @param pointerY 当前鼠标在容器中的 Y 坐标
|
||||||
|
* @returns 限制后的坐标点 { x, y }
|
||||||
|
*/
|
||||||
|
private applyBoundary(x: number, y: number, pointerX: number, pointerY: number): { x: number; y: number } {
|
||||||
|
const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
|
||||||
|
|
||||||
|
// 限制指针在容器内
|
||||||
|
const limitedPointerX = Math.min(Math.max(pointerX, containerRect.left), containerRect.right)
|
||||||
|
const limitedPointerY = Math.min(Math.max(pointerY, containerRect.top), containerRect.bottom)
|
||||||
|
|
||||||
|
// 计算指针被限制后的偏移量
|
||||||
|
const dx = limitedPointerX - pointerX
|
||||||
|
const dy = limitedPointerY - pointerY
|
||||||
|
|
||||||
|
// 根据指针偏移调整窗口位置
|
||||||
|
x += dx
|
||||||
|
y += dy
|
||||||
|
|
||||||
|
return { x, y }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置拖拽的窗口位置
|
||||||
|
* @param x 当前元素的左上角坐标点 x
|
||||||
|
* @param y 当前元素的左上角坐标点 y
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private applyPosition(x: number, y: number) {
|
||||||
this.x = x
|
this.x = x
|
||||||
this.y = y
|
this.y = y
|
||||||
this.style.transform = `translate(${x}px, ${y}px)`
|
this.style.transform = `translate(${x}px, ${y}px)`
|
||||||
if (isFinal) this.applyBoundary()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private applyBoundary() {
|
/**
|
||||||
if (this.allowOverflow) return
|
* 动画移动窗口
|
||||||
let { x, y } = { x: this.x, y: this.y }
|
* @param startX 窗口起始点 x
|
||||||
|
* @param startY 窗口起始点 y
|
||||||
const rect = this.getBoundingClientRect()
|
* @param targetX 目标点 x
|
||||||
const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
|
* @param targetY 目标点 y
|
||||||
x = Math.min(Math.max(x, 0), containerRect.width - rect.width)
|
* @param duration 动画时长
|
||||||
y = Math.min(Math.max(y, 0), containerRect.height - rect.height)
|
* @param onMove 移动回调
|
||||||
|
* @param onComplete 完成回调
|
||||||
this.applyPosition(x, y, false)
|
* @private
|
||||||
}
|
*/
|
||||||
|
private animateTo(
|
||||||
private animateTo(targetX: number, targetY: number, duration: number, onComplete?: () => void) {
|
startX: number,
|
||||||
|
startY: number,
|
||||||
|
targetX: number,
|
||||||
|
targetY: number,
|
||||||
|
duration: number,
|
||||||
|
onMove?: (x: number, y: number) => void,
|
||||||
|
onComplete?: (x: number, y: number) => void
|
||||||
|
) {
|
||||||
if (this.animationFrame) cancelAnimationFrame(this.animationFrame)
|
if (this.animationFrame) cancelAnimationFrame(this.animationFrame)
|
||||||
const startX = this.x
|
|
||||||
const startY = this.y
|
|
||||||
const deltaX = targetX - startX
|
const deltaX = targetX - startX
|
||||||
const deltaY = targetY - startY
|
const deltaY = targetY - startY
|
||||||
const startTime = performance.now()
|
const startTime = performance.now()
|
||||||
@@ -404,7 +471,7 @@ export class WindowFormElement extends LitElement {
|
|||||||
const x = startX + deltaX * ease
|
const x = startX + deltaX * ease
|
||||||
const y = startY + deltaY * ease
|
const y = startY + deltaY * ease
|
||||||
|
|
||||||
this.applyPosition(x, y, false)
|
onMove?.(x, y)
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:dragMove', {
|
new CustomEvent('windowForm:dragMove', {
|
||||||
detail: { x, y },
|
detail: { x, y },
|
||||||
@@ -416,8 +483,7 @@ export class WindowFormElement extends LitElement {
|
|||||||
if (progress < 1) {
|
if (progress < 1) {
|
||||||
this.animationFrame = requestAnimationFrame(step)
|
this.animationFrame = requestAnimationFrame(step)
|
||||||
} else {
|
} else {
|
||||||
this.applyPosition(targetX, targetY, true)
|
onComplete?.(targetX, targetY)
|
||||||
onComplete?.()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.animationFrame = requestAnimationFrame(step)
|
this.animationFrame = requestAnimationFrame(step)
|
||||||
@@ -432,14 +498,12 @@ export class WindowFormElement extends LitElement {
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
this.resizing = true
|
this.resizing = true
|
||||||
this.resizeDir = dir
|
this.resizeDir = dir
|
||||||
this.startX = e.clientX
|
this.pointStartX = e.clientX
|
||||||
this.startY = e.clientY
|
this.pointStartY = e.clientY
|
||||||
|
this.originalX = this.x
|
||||||
const rect = this.getBoundingClientRect()
|
this.originalY = this.y
|
||||||
this.startWidth = rect.width
|
this.originalWidth = this.width
|
||||||
this.startHeight = rect.height
|
this.originalHeight = this.height
|
||||||
this.startX_host = rect.left
|
|
||||||
this.startY_host = rect.top
|
|
||||||
|
|
||||||
const target = e.target as HTMLElement
|
const target = e.target as HTMLElement
|
||||||
document.body.style.cursor = target.style.cursor || window.getComputedStyle(target).cursor
|
document.body.style.cursor = target.style.cursor || window.getComputedStyle(target).cursor
|
||||||
@@ -454,59 +518,72 @@ export class WindowFormElement extends LitElement {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩放
|
||||||
|
* @param e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private performResize(e: PointerEvent) {
|
private performResize(e: PointerEvent) {
|
||||||
if (!this.resizeDir || !this.resizing) return
|
if (!this.resizeDir || !this.resizing) return
|
||||||
|
|
||||||
let newWidth = this.startWidth
|
let newWidth = this.originalWidth
|
||||||
let newHeight = this.startHeight
|
let newHeight = this.originalHeight
|
||||||
let newX = this.startX_host
|
let newX = this.originalX
|
||||||
let newY = this.startY_host
|
let newY = this.originalY
|
||||||
|
|
||||||
const dx = e.clientX - this.startX
|
const dx = e.clientX - this.pointStartX
|
||||||
const dy = e.clientY - this.startY
|
const dy = e.clientY - this.pointStartY
|
||||||
|
|
||||||
|
// ====== 根据方向计算临时尺寸与位置 ======
|
||||||
switch (this.resizeDir) {
|
switch (this.resizeDir) {
|
||||||
case 'r':
|
case 'r': // 右侧
|
||||||
newWidth += dx
|
newWidth += dx
|
||||||
break
|
break
|
||||||
case 'b':
|
case 'b': // 下方
|
||||||
newHeight += dy
|
newHeight += dy
|
||||||
break
|
break
|
||||||
case 'l':
|
case 'l': // 左侧
|
||||||
newWidth -= dx
|
newWidth -= dx
|
||||||
newX += dx
|
newX += dx
|
||||||
break
|
break
|
||||||
case 't':
|
case 't': // 上方
|
||||||
newHeight -= dy
|
newHeight -= dy
|
||||||
newY += dy
|
newY += dy
|
||||||
break
|
break
|
||||||
case 'tl':
|
case 'tl': // 左上角
|
||||||
newWidth -= dx
|
newWidth -= dx
|
||||||
newX += dx
|
newX += dx
|
||||||
newHeight -= dy
|
newHeight -= dy
|
||||||
newY += dy
|
newY += dy
|
||||||
break
|
break
|
||||||
case 'tr':
|
case 'tr': // 右上角
|
||||||
newWidth += dx
|
newWidth += dx
|
||||||
newHeight -= dy
|
newHeight -= dy
|
||||||
newY += dy
|
newY += dy
|
||||||
break
|
break
|
||||||
case 'bl':
|
case 'bl': // 左下角
|
||||||
newWidth -= dx
|
newWidth -= dx
|
||||||
newX += dx
|
newX += dx
|
||||||
newHeight += dy
|
newHeight += dy
|
||||||
break
|
break
|
||||||
case 'br':
|
case 'br': // 右下角
|
||||||
newWidth += dx
|
newWidth += dx
|
||||||
newHeight += dy
|
newHeight += dy
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
const d = this.applyResizeBounds(newX, newY, newWidth, newHeight)
|
const { x, y, width, height } = this.applyResizeBounds(newX, newY, newWidth, newHeight, this.resizeDir)
|
||||||
|
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.width = width
|
||||||
|
this.height = height
|
||||||
|
this.style.width = `${this.width}px`
|
||||||
|
this.style.height = `${this.height}px`
|
||||||
|
this.style.transform = `translate(${this.x}px, ${this.y}px)`
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:resizeMove', {
|
new CustomEvent('windowForm:resizeMove', {
|
||||||
detail: { dir: this.resizeDir, width: d.width, height: d.height, left: d.left, top: d.top },
|
detail: { dir: this.resizeDir, width: width, height: height, left: x, top: y },
|
||||||
bubbles: true,
|
bubbles: true,
|
||||||
composed: true,
|
composed: true,
|
||||||
}),
|
}),
|
||||||
@@ -514,68 +591,107 @@ export class WindowFormElement extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 应用尺寸调整边界
|
* 计算尺寸调整约束逻辑,返回约束后的尺寸
|
||||||
* @param newX 新的X坐标
|
* @param x 坐标 x
|
||||||
* @param newY 新的Y坐标
|
* @param y 坐标 y
|
||||||
* @param newWidth 新的宽度
|
* @param width 宽度
|
||||||
* @param newHeight 新的高度
|
* @param height 高度
|
||||||
* @private
|
* @private
|
||||||
|
* @returns { x: number, y: number, width: number, height: number } 约束后的尺寸
|
||||||
*/
|
*/
|
||||||
private applyResizeBounds(
|
private applyResizeBounds(
|
||||||
newX: number,
|
x: number,
|
||||||
newY: number,
|
y: number,
|
||||||
newWidth: number,
|
width: number,
|
||||||
newHeight: number,
|
height: number,
|
||||||
|
resizeDir: TResizeDirection
|
||||||
): {
|
): {
|
||||||
left: number
|
x: number
|
||||||
top: number
|
y: number
|
||||||
width: number
|
width: number
|
||||||
height: number
|
height: number
|
||||||
} {
|
} {
|
||||||
// 最小/最大宽高限制
|
const { minWidth = 100, minHeight = 100, maxWidth = Infinity, maxHeight = Infinity } = this
|
||||||
if (this.minWidth != null) newWidth = Math.max(this.minWidth, newWidth)
|
|
||||||
if (this.maxWidth != null) newWidth = Math.min(this.maxWidth, newWidth)
|
|
||||||
if (this.minHeight != null) newHeight = Math.max(this.minHeight, newHeight)
|
|
||||||
if (this.maxHeight != null) newHeight = Math.min(this.maxHeight, newHeight)
|
|
||||||
|
|
||||||
// 边界限制
|
//#region 限制最大/最小尺寸
|
||||||
if (this.allowOverflow) {
|
// 限制宽度
|
||||||
this.x = newX
|
if (width < minWidth) {
|
||||||
this.y = newY
|
// 左缩时要修正X坐标,否则会跳动
|
||||||
this.width = newWidth
|
if (resizeDir.includes('l')) x -= minWidth - width
|
||||||
this.height = newHeight
|
width = minWidth
|
||||||
this.style.width = `${newWidth}px`
|
} else if (width > maxWidth) {
|
||||||
this.style.height = `${newHeight}px`
|
if (resizeDir.includes('l')) x += width - maxWidth
|
||||||
this.applyPosition(newX, newY, false)
|
width = maxWidth
|
||||||
|
|
||||||
return {
|
|
||||||
left: newX,
|
|
||||||
top: newY,
|
|
||||||
width: newWidth,
|
|
||||||
height: newHeight,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 限制高度
|
||||||
|
if (height < minHeight) {
|
||||||
|
if (resizeDir.includes('t')) y -= minHeight - height
|
||||||
|
height = minHeight
|
||||||
|
} else if (height > maxHeight) {
|
||||||
|
if (resizeDir.includes('t')) y += height - maxHeight
|
||||||
|
height = maxHeight
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
//#region 限制在容器边界内
|
||||||
const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
|
const containerRect = (this.dragContainer || document.body).getBoundingClientRect()
|
||||||
newX = Math.min(Math.max(0, newX), containerRect.width - newWidth)
|
const maxLeft = containerRect.width - width
|
||||||
newY = Math.min(Math.max(0, newY), containerRect.height - newHeight)
|
const maxTop = containerRect.height - height
|
||||||
|
|
||||||
this.x = newX
|
// 左越界(从左侧缩放时)
|
||||||
this.y = newY
|
if (x < 0) {
|
||||||
this.width = newWidth
|
if (resizeDir.includes('l')) {
|
||||||
this.height = newHeight
|
// 如果是往左拉出容器,锁定边界
|
||||||
this.style.width = `${newWidth}px`
|
width += x // 因为x是负数,相当于减小宽度
|
||||||
this.style.height = `${newHeight}px`
|
}
|
||||||
this.applyPosition(newX, newY, false)
|
x = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 顶部越界(从上侧缩放时)
|
||||||
|
if (y < 0) {
|
||||||
|
if (resizeDir.includes('t')) {
|
||||||
|
height += y // y是负数,相当于减小高度
|
||||||
|
}
|
||||||
|
y = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 右越界(从右侧缩放时)
|
||||||
|
if (x + width > containerRect.width) {
|
||||||
|
if (resizeDir.includes('r')) {
|
||||||
|
width = containerRect.width - x
|
||||||
|
} else {
|
||||||
|
x = Math.min(x, maxLeft)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部越界(从下侧缩放时)
|
||||||
|
if (y + height > containerRect.height) {
|
||||||
|
if (resizeDir.includes('b')) {
|
||||||
|
height = containerRect.height - y
|
||||||
|
} else {
|
||||||
|
y = Math.min(y, maxTop)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
|
// 二次防护:确保不小于最小值
|
||||||
|
width = Math.max(width, minWidth)
|
||||||
|
height = Math.max(height, minHeight)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
left: newX,
|
x,
|
||||||
top: newY,
|
y,
|
||||||
width: newWidth,
|
width,
|
||||||
height: newHeight,
|
height
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缩放结束
|
||||||
|
* @param e
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
private resizeUp(e: PointerEvent) {
|
private resizeUp(e: PointerEvent) {
|
||||||
if (!this.resizable) return
|
if (!this.resizable) return
|
||||||
|
|
||||||
@@ -617,12 +733,16 @@ export class WindowFormElement extends LitElement {
|
|||||||
startY,
|
startY,
|
||||||
startW,
|
startW,
|
||||||
startH,
|
startH,
|
||||||
rect.left,
|
rect.x,
|
||||||
rect.top,
|
rect.y,
|
||||||
rect.width,
|
rect.width,
|
||||||
rect.height,
|
rect.height,
|
||||||
400,
|
400,
|
||||||
() => {
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
|
},
|
||||||
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
this.style.display = 'none'
|
this.style.display = 'none'
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:stateChange:minimize', {
|
new CustomEvent('windowForm:stateChange:minimize', {
|
||||||
@@ -667,7 +787,11 @@ export class WindowFormElement extends LitElement {
|
|||||||
targetW,
|
targetW,
|
||||||
targetH,
|
targetH,
|
||||||
300,
|
300,
|
||||||
() => {
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
|
},
|
||||||
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:stateChange:maximize', {
|
new CustomEvent('windowForm:stateChange:maximize', {
|
||||||
detail: { state: this.windowFormState },
|
detail: { state: this.windowFormState },
|
||||||
@@ -713,12 +837,16 @@ export class WindowFormElement extends LitElement {
|
|||||||
startY,
|
startY,
|
||||||
startW,
|
startW,
|
||||||
startH,
|
startH,
|
||||||
b.left,
|
b.x,
|
||||||
b.top,
|
b.y,
|
||||||
b.width,
|
b.width,
|
||||||
b.height,
|
b.height,
|
||||||
300,
|
300,
|
||||||
() => {
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
|
},
|
||||||
|
(x, y, w, h) => {
|
||||||
|
this.applyWindowStyle(x, y, w, h)
|
||||||
onComplete?.()
|
onComplete?.()
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:stateChange:restore', {
|
new CustomEvent('windowForm:stateChange:restore', {
|
||||||
@@ -731,6 +859,24 @@ export class WindowFormElement extends LitElement {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 应用窗体样式
|
||||||
|
* @param x
|
||||||
|
* @param y
|
||||||
|
* @param w
|
||||||
|
* @param h
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
private applyWindowStyle(x: number, y: number, w: number, h: number) {
|
||||||
|
this.width = w
|
||||||
|
this.height = h
|
||||||
|
this.x = x
|
||||||
|
this.y = y
|
||||||
|
this.style.width = `${w}px`
|
||||||
|
this.style.height = `${h}px`
|
||||||
|
this.style.transform = `translate(${x}px, ${y}px)`
|
||||||
|
}
|
||||||
|
|
||||||
private windowFormClose() {
|
private windowFormClose() {
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:close', {
|
new CustomEvent('windowForm:close', {
|
||||||
@@ -764,7 +910,8 @@ export class WindowFormElement extends LitElement {
|
|||||||
targetW: number,
|
targetW: number,
|
||||||
targetH: number,
|
targetH: number,
|
||||||
duration: number,
|
duration: number,
|
||||||
onComplete?: () => void,
|
onUpdating?: (x: number, y: number, w: number, h: number) => void,
|
||||||
|
onComplete?: (x: number, y: number, w: number, h: number) => void,
|
||||||
) {
|
) {
|
||||||
const startTime = performance.now()
|
const startTime = performance.now()
|
||||||
const step = (now: number) => {
|
const step = (now: number) => {
|
||||||
@@ -777,17 +924,14 @@ export class WindowFormElement extends LitElement {
|
|||||||
const w = startW + (targetW - startW) * ease
|
const w = startW + (targetW - startW) * ease
|
||||||
const h = startH + (targetH - startH) * ease
|
const h = startH + (targetH - startH) * ease
|
||||||
|
|
||||||
this.style.width = `${w}px`
|
onUpdating?.(x, y, w, h)
|
||||||
this.style.height = `${h}px`
|
|
||||||
this.applyPosition(x, y, false)
|
|
||||||
|
|
||||||
if (progress < 1) {
|
if (progress < 1) {
|
||||||
requestAnimationFrame(step)
|
requestAnimationFrame(step)
|
||||||
} else {
|
} else {
|
||||||
this.style.width = `${targetW}px`
|
this.style.width = `${targetW}px`
|
||||||
this.style.height = `${targetH}px`
|
this.style.height = `${targetH}px`
|
||||||
this.applyPosition(targetX, targetY, true)
|
onComplete?.(x, y, w, h)
|
||||||
onComplete?.()
|
|
||||||
this.dispatchEvent(
|
this.dispatchEvent(
|
||||||
new CustomEvent('windowForm:stateChange', {
|
new CustomEvent('windowForm:stateChange', {
|
||||||
detail: { state: this.windowFormState },
|
detail: { state: this.windowFormState },
|
||||||
@@ -800,10 +944,10 @@ export class WindowFormElement extends LitElement {
|
|||||||
requestAnimationFrame(step)
|
requestAnimationFrame(step)
|
||||||
}
|
}
|
||||||
|
|
||||||
private updateTargetBounds(left: number, top: number, width?: number, height?: number) {
|
private updateTargetBounds(x: number, y: number, width?: number, height?: number) {
|
||||||
this.targetBounds = {
|
this.targetBounds = {
|
||||||
left,
|
x,
|
||||||
top,
|
y,
|
||||||
width: width ?? this.offsetWidth,
|
width: width ?? this.offsetWidth,
|
||||||
height: height ?? this.offsetHeight,
|
height: height ?? this.offsetHeight,
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user