From d37d92996a452e86f00313cf7c3c20badf757f57 Mon Sep 17 00:00:00 2001 From: ZhangAo Date: Fri, 19 Sep 2025 17:29:19 +0800 Subject: [PATCH] u --- .../packages/ao-design/src/modal/index.scss | 3 +- .../packages/ao-design/src/modal/index.tsx | 199 +++++++++--------- code/base-project/base-vue/src/App.vue | 17 +- 3 files changed, 113 insertions(+), 106 deletions(-) diff --git a/code/base-project/base-vue/packages/ao-design/src/modal/index.scss b/code/base-project/base-vue/packages/ao-design/src/modal/index.scss index 1d90eb1f..2b1b762e 100644 --- a/code/base-project/base-vue/packages/ao-design/src/modal/index.scss +++ b/code/base-project/base-vue/packages/ao-design/src/modal/index.scss @@ -40,6 +40,7 @@ $btn-prefix: '#{$prefix}-btn'; justify-content: center; width: 100%; height: 100%; + overflow: visible; .#{$modal-prefix} { background: #fff; @@ -59,7 +60,6 @@ $btn-prefix: '#{$prefix}-btn'; width: 100%; font-size: 16px; padding: 12px 16px; - border-bottom: 1px solid $separator-color; word-break: break-all; } @@ -111,7 +111,6 @@ $btn-prefix: '#{$prefix}-btn'; &-footer { padding: 12px 16px; flex-shrink: 0; - border-top: 1px solid $separator-color; text-align: right; .#{$btn-prefix}:not(:first-child) { margin-left: 12px; diff --git a/code/base-project/base-vue/packages/ao-design/src/modal/index.tsx b/code/base-project/base-vue/packages/ao-design/src/modal/index.tsx index ea8f0f52..2b11f8ad 100644 --- a/code/base-project/base-vue/packages/ao-design/src/modal/index.tsx +++ b/code/base-project/base-vue/packages/ao-design/src/modal/index.tsx @@ -1,4 +1,4 @@ -import type { PropType, Ref } from 'vue' +import type { PropType } from 'vue' import { computed, defineComponent, onMounted, ref, Teleport, Transition, watch } from 'vue' import { getPrefixCls } from '../_utils/getPrefixCls' import Button from '../button/index' @@ -7,32 +7,81 @@ import Icon from '../icon/index' export default defineComponent({ name: 'Modal', props: { - visible: { type: Boolean, default: undefined }, - defaultVisible: { type: Boolean, default: false }, - mask: { type: Boolean, default: true }, - maskClosable: { type: Boolean, default: true }, - position: { type: String as PropType<'top' | 'center' | 'bottom'>, default: 'center' }, - type: { type: String as PropType<'default' | 'info' | 'success' | 'warning' | 'danger' | 'question'>, default: 'default' }, - showClose: { type: Boolean, default: true }, - confirmBtn: { type: null, default: () => ({ label: '确认', type: 'solid', status: 'primary', size: 'small' }) }, - cancelBtn: { type: null, default: () => ({ label: '取消', type: 'solid', status: 'default', size: 'small' }) }, - onBeforeConfirm: { type: Function as PropType<(done: (ok: boolean) => void) => void | boolean | Promise> }, - onBeforeCancel: { type: Function as PropType<(done: (ok: boolean) => void) => void | boolean | Promise> }, - destroyOnClose: { type: Boolean, default: false }, - appendTo: { type: [String, Object] as PropType, default: 'body' }, - fullscreen: { type: Boolean, default: false }, - draggable: { type: Boolean, default: false }, - draggableBoundary: { type: Boolean, default: false }, - draggableRef: { type: Object as PropType | null>, default: null }, - class: { type: [String, Array, Object], default: '' }, - style: { type: Object, default: () => ({}) }, + visible: { + type: Boolean, + default: undefined, + }, + defaultVisible: { + type: Boolean, + default: false, + }, + mask: { + type: Boolean, + default: true, + }, + maskClosable: { + type: Boolean, + default: true, + }, + position: { + type: String as PropType<'top' | 'center' | 'bottom'>, + default: 'center', + }, + type: { + type: String as PropType<'default' | 'info' | 'success' | 'warning' | 'danger' | 'question'>, + default: 'default', + }, + showClose: { + type: Boolean, + default: true, + }, + confirmBtn: { + type: null, + default: () => ({ label: '确认', type: 'solid', status: 'primary', size: 'small' }), + }, + cancelBtn: { + type: null, + default: () => ({ label: '取消', type: 'solid', status: 'default', size: 'small' }), + }, + destroyOnClose: { + type: Boolean, + default: false, + }, + appendTo: { + type: [String, Object] as PropType, + default: 'body', + }, + fullscreen: { + type: Boolean, + default: false, + }, + draggable: { + type: Boolean, + default: false, + }, + draggableBoundary: { + type: Boolean, + default: false, + }, + draggableSelector: { + type: String, + default: '', + }, // 拖拽区域选择器 + class: { + type: [String, Array, Object], + default: '', + }, + style: { + type: Object, + default: () => ({}), + }, }, emits: ['update:visible', 'confirm', 'cancel', 'open', 'close', 'beforeOpen', 'beforeClose'], setup(props, { slots, emit }) { const prefixCls = getPrefixCls('modal') const targetEl = ref(document.body) - const confirmLoading = ref(false) const modalRef = ref() + const confirmLoading = ref(false) const _visible = ref(props.defaultVisible) const isVisible = computed(() => props.visible ?? _visible.value) @@ -69,48 +118,15 @@ export default defineComponent({ } const handleCancel = async () => { - let allow = true - if (props.onBeforeCancel) { - try { - allow = await new Promise((resolve) => { - const result = props.onBeforeCancel!(ok => resolve(ok)) - if (typeof result === 'boolean') - resolve(result) - else if (result instanceof Promise) - result.then(resolve).catch(() => resolve(false)) - }) - } - catch { allow = false } - } - if (allow) { - emit('update:visible', false) - emit('cancel') - confirmLoading.value = false - } + emit('update:visible', false) + emit('cancel') + confirmLoading.value = false } - const handleConfirm = async () => { - let allow = true - if (props.onBeforeConfirm) { - confirmLoading.value = true - try { - allow = await new Promise((resolve) => { - const result = props.onBeforeConfirm!(ok => resolve(ok)) - if (typeof result === 'boolean') - resolve(result) - else if (result instanceof Promise) - result.then(resolve).catch(() => resolve(false)) - }) - } - catch { allow = false } - } - if (allow) { - emit('update:visible', false) - emit('confirm') - } + emit('update:visible', false) + emit('confirm') confirmLoading.value = false } - const handleAfterEnter = () => emit('open') const handleAfterLeave = () => { isRootVisible.value = false @@ -125,28 +141,21 @@ export default defineComponent({ const handleMouseMove = (e: MouseEvent) => { if (!dragData.dragging || !modalRef.value) return - const modal = modalRef.value - const rect = modal.getBoundingClientRect() - let newLeft = e.clientX - dragData.offsetX - let newTop = e.clientY - dragData.offsetY + const rect = modalRef.value.getBoundingClientRect() + let left = e.clientX - dragData.offsetX + let top = e.clientY - dragData.offsetY if (props.draggableBoundary) { - const winWidth = window.innerWidth - const winHeight = window.innerHeight - if (newLeft < 0) - newLeft = 0 - if (newTop < 0) - newTop = 0 - if (newLeft + rect.width > winWidth) - newLeft = winWidth - rect.width - if (newTop + rect.height > winHeight) - newTop = winHeight - rect.height + const w = window.innerWidth + const h = window.innerHeight + left = Math.min(Math.max(0, left), w - rect.width) + top = Math.min(Math.max(0, top), h - rect.height) } - modal.style.left = `${newLeft}px` - modal.style.top = `${newTop}px` - modal.style.position = 'absolute' - modal.style.transform = '' + modalRef.value.style.left = `${left}px` + modalRef.value.style.top = `${top}px` + modalRef.value.style.position = 'absolute' + modalRef.value.style.transform = '' } const handleMouseUp = () => { @@ -156,21 +165,23 @@ export default defineComponent({ } const handleMouseDown = (e: MouseEvent) => { - if (!modalRef.value) + if (!props.draggable || !modalRef.value) return - let dragTarget: HTMLElement | null = null + // 自动选择拖拽区域 + let dragEl: HTMLElement | null = null - // 如果传了 ref - if (props.draggableRef?.value) { - dragTarget = props.draggableRef.value + if (props.draggableSelector) { + dragEl = modalRef.value.querySelector(props.draggableSelector) } - // 否则默认 header else { - dragTarget = modalRef.value.querySelector(`.${prefixCls}-header`) + dragEl = modalRef.value.querySelector(`.${prefixCls}-header`) } + // 如果没找到,默认拖动整个 modal + if (!dragEl) + dragEl = modalRef.value - if (!dragTarget || !dragTarget.contains(e.target as Node)) + if (!dragEl.contains(e.target as Node)) return dragData.dragging = true @@ -199,22 +210,22 @@ export default defineComponent({
)} - +
-
+
{props.type !== 'default' && } {slots.title?.()} diff --git a/code/base-project/base-vue/src/App.vue b/code/base-project/base-vue/src/App.vue index 1a173a2f..4b2bec87 100644 --- a/code/base-project/base-vue/src/App.vue +++ b/code/base-project/base-vue/src/App.vue @@ -18,16 +18,13 @@ const dragHandle = ref(null) 打开 Header 拖拽 - - - -
- 拖拽这个区域 (ref) -
-

Modal 内容

-
+ +
+ 拖拽这里 +
+

Modal 内容

+
+ 打开 Ref 拖拽