From e6affad67fed5e815563396e7ce6ab816ee737ce Mon Sep 17 00:00:00 2001 From: lt5227 <995362096@qq.com> Date: Thu, 5 Sep 2024 18:21:57 +0800 Subject: [PATCH] feat: The dialog supports custom-defined window size. #527 --- src/components/Dialog/hooks/useResize.ts | 178 +++++++++++++++++++++ src/components/Dialog/src/Dialog.vue | 7 + src/components/Dialog/src/ResizeDialog.vue | 73 +++++++++ src/locales/en.ts | 1 + src/locales/zh-CN.ts | 1 + src/views/Components/Dialog.vue | 34 ++++ 6 files changed, 294 insertions(+) create mode 100644 src/components/Dialog/hooks/useResize.ts create mode 100644 src/components/Dialog/src/ResizeDialog.vue diff --git a/src/components/Dialog/hooks/useResize.ts b/src/components/Dialog/hooks/useResize.ts new file mode 100644 index 0000000..d52b279 --- /dev/null +++ b/src/components/Dialog/hooks/useResize.ts @@ -0,0 +1,178 @@ +import { ref } from 'vue' + +export const useResize = (props?: { + minHeightPx?: number + minWidthPx?: number + initHeight?: number + initWidth?: number +}) => { + const { + minHeightPx = 400, + minWidthPx = window.innerWidth / 2, + initHeight = 400, + initWidth = window.innerWidth / 2 + } = props || {} + // 屏幕宽度的 50% 作为最小宽度 + // const minWidthPx = window.innerWidth / 2 + // 固定的最小高度 400px + // const minHeightPx = 400 + // 初始高度限制为 400px + const maxHeight = ref(initHeight + 'px') + // 初始宽度限制为 50% + const minWidth = ref(initWidth + 'px') + const setupDrag = (elDialog: any, el: any) => { + // 获取对话框元素 + // 是否正在调整大小的标志 + let isResizing = false + // 当前调整的方向 + let currentResizeDirection = '' + + // 鼠标移动时的事件处理器,用于检测鼠标位置并设置相应的光标样式 + const handleMouseMove = (e: any) => { + const rect = elDialog.getBoundingClientRect() + // 鼠标相对于对话框左侧的偏移量 + const offsetX = e.clientX - rect.left + // 鼠标相对于对话框顶部的偏移量 + const offsetY = e.clientY - rect.top + const width = elDialog.clientWidth + const height = elDialog.clientHeight + + // 获取对话框的内边距 + const computedStyle = window.getComputedStyle(elDialog) + const paddingLeft = parseFloat(computedStyle.paddingLeft) + const paddingRight = parseFloat(computedStyle.paddingRight) + const paddingBottom = parseFloat(computedStyle.paddingBottom) + const paddingTop = parseFloat(computedStyle.paddingTop) + + // 根据鼠标位置设置相应的光标样式和调整方向 + if (!isResizing) { + if (offsetX < paddingLeft && offsetY > paddingTop && offsetY < height - paddingBottom) { + elDialog.style.cursor = 'ew-resize' // 左右箭头 + currentResizeDirection = 'left' + } else if ( + offsetX > width - paddingRight && + offsetY > paddingTop && + offsetY < height - paddingBottom + ) { + elDialog.style.cursor = 'ew-resize' // 左右箭头 + currentResizeDirection = 'right' + } else if ( + offsetY < paddingTop && + offsetX > paddingLeft && + offsetX < width - paddingRight + ) { + elDialog.style.cursor = 'ns-resize' // 上下箭头 + currentResizeDirection = 'top' + } else if ( + offsetY > height - paddingBottom && + offsetX > paddingLeft && + offsetX < width - paddingRight + ) { + elDialog.style.cursor = 'ns-resize' // 上下箭头 + currentResizeDirection = 'bottom' + } else if (offsetX < paddingLeft && offsetY < paddingTop) { + elDialog.style.cursor = 'nwse-resize' // 左上右下箭头 + currentResizeDirection = 'top-left' + } else if (offsetX > width - paddingRight && offsetY < paddingTop) { + elDialog.style.cursor = 'nesw-resize' // 右上左下箭头 + currentResizeDirection = 'top-right' + } else if (offsetX < paddingLeft && offsetY > height - paddingBottom) { + elDialog.style.cursor = 'nesw-resize' // 右上左下箭头 + currentResizeDirection = 'bottom-left' + } else if (offsetX > width - paddingRight && offsetY > height - paddingBottom) { + elDialog.style.cursor = 'nwse-resize' // 左上右下箭头 + currentResizeDirection = 'bottom-right' + } else { + elDialog.style.cursor = 'default' + currentResizeDirection = '' + } + } + } + + // 鼠标按下时的事件处理器,开始调整对话框大小 + const handleMouseDown = (e) => { + if (currentResizeDirection) { + isResizing = true + + const initialX = e.clientX + const initialY = e.clientY + const initialWidth = elDialog.clientWidth + const initialHeight = el.querySelector('.el-dialog__body').clientHeight + + // 调整大小的事件处理器 + const handleResizing = (e: any) => { + if (!isResizing) return + + let newWidth = initialWidth + let newHeight = initialHeight + + // 根据当前调整方向计算新的宽度和高度 + if (currentResizeDirection.includes('right')) { + newWidth = Math.max(minWidthPx, initialWidth + (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + } + + if (currentResizeDirection.includes('left')) { + newWidth = Math.max(minWidthPx, initialWidth - (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + } + + if (currentResizeDirection.includes('bottom')) { + newHeight = Math.max(minHeightPx, initialHeight + (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + + if (currentResizeDirection.includes('top')) { + newHeight = Math.max(minHeightPx, initialHeight - (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + + if (currentResizeDirection === 'top-left') { + newWidth = Math.max(minWidthPx, initialWidth - (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + newHeight = Math.max(minHeightPx, initialHeight - (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + + if (currentResizeDirection === 'top-right') { + newWidth = Math.max(minWidthPx, initialWidth + (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + newHeight = Math.max(minHeightPx, initialHeight - (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + + if (currentResizeDirection === 'bottom-left') { + newWidth = Math.max(minWidthPx, initialWidth - (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + newHeight = Math.max(minHeightPx, initialHeight + (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + + if (currentResizeDirection === 'bottom-right') { + newWidth = Math.max(minWidthPx, initialWidth + (e.clientX - initialX) * 2) + minWidth.value = `${newWidth}px` + newHeight = Math.max(minHeightPx, initialHeight + (e.clientY - initialY) * 2 - 20) + maxHeight.value = `${Math.min(newHeight, window.innerHeight - 165)}px` + } + } + // 停止调整大小的事件处理器 + const stopResizing = () => { + isResizing = false + document.removeEventListener('mousemove', handleResizing) + document.removeEventListener('mouseup', stopResizing) + } + + document.addEventListener('mousemove', handleResizing) + document.addEventListener('mouseup', stopResizing) + } + } + elDialog.addEventListener('mousemove', handleMouseMove) + elDialog.addEventListener('mousedown', handleMouseDown) + } + + return { + setupDrag, + maxHeight, + minWidth + } +} diff --git a/src/components/Dialog/src/Dialog.vue b/src/components/Dialog/src/Dialog.vue index 9534db0..611d702 100644 --- a/src/components/Dialog/src/Dialog.vue +++ b/src/components/Dialog/src/Dialog.vue @@ -49,6 +49,13 @@ watch( } ) +watch( + () => props.maxHeight, + (val) => { + dialogHeight.value = isNumber(val) ? `${val}px` : val + } +) + const dialogStyle = computed(() => { return { height: unref(dialogHeight) diff --git a/src/components/Dialog/src/ResizeDialog.vue b/src/components/Dialog/src/ResizeDialog.vue new file mode 100644 index 0000000..d604e12 --- /dev/null +++ b/src/components/Dialog/src/ResizeDialog.vue @@ -0,0 +1,73 @@ + + diff --git a/src/locales/en.ts b/src/locales/en.ts index f038abf..f26eb8f 100644 --- a/src/locales/en.ts +++ b/src/locales/en.ts @@ -480,6 +480,7 @@ export default { }, dialogDemo: { dialog: 'Dialog', + resizeDialog: 'Resize dialog', dialogDes: 'Secondary packaging of Dialog components based on ElementPlus', open: 'Open', close: 'Close', diff --git a/src/locales/zh-CN.ts b/src/locales/zh-CN.ts index a4df161..8f38c0a 100644 --- a/src/locales/zh-CN.ts +++ b/src/locales/zh-CN.ts @@ -471,6 +471,7 @@ export default { }, dialogDemo: { dialog: '弹窗', + resizeDialog: '可自定义调节弹窗大小的弹窗', dialogDes: '基于 ElementPlus 的 Dialog 组件二次封装', open: '打开', close: '关闭', diff --git a/src/views/Components/Dialog.vue b/src/views/Components/Dialog.vue index cd7e16a..33726e4 100644 --- a/src/views/Components/Dialog.vue +++ b/src/views/Components/Dialog.vue @@ -8,6 +8,7 @@ import { useValidator } from '@/hooks/web/useValidator' import { getDictOneApi } from '@/api/common' import { useForm } from '@/hooks/web/useForm' import Echart from './Echart.vue' +import ResizeDialog from '@/components/Dialog/src/ResizeDialog.vue' const { required } = useValidator() @@ -17,6 +18,10 @@ const dialogVisible = ref(false) const dialogVisible2 = ref(false) +const dialogVisible3 = ref(false) + +const dialogVisible4 = ref(false) + const { formRegister, formMethods } = useForm() const { getElFormExpose } = formMethods @@ -128,4 +133,33 @@ const formSubmit = async () => { + + + + {{ t('dialogDemo.open') }} + + + + {{ t('dialogDemo.combineWithForm') }} + + + + + + + + +
+ + +