| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- <template>
- <a-modal ref="modalRef" width="850px" :visible="props.visible" :wrap-style="{ overflow: 'hidden' }" @ok="handleOk"
- :mask-closable="maskClosable" :centered="props.centered" :footer="props.footer" @cancel="handleCancel"
- :confirm-loading="props.confirmLoading" :destroyOnClose="props.destroyOnClose">
- <slot></slot>
- <template #title>
- <div ref="modalTitleRef" style="width: 100%; cursor: move">{{ props.title }}</div>
- </template>
- <template #modalRender="{ originVNode }">
- <div :style="transformStyle">
- <component :is="originVNode" />
- </div>
- </template>
- </a-modal>
- </template>
- <script lang="ts" setup>
- import { computed, CSSProperties, ref, watch, watchEffect } from "vue";
- import { useDraggable } from "@vueuse/core";
- // 定义Props接口,描述组件的属性
- interface Props {
- title?: string, // 对话框的标题,默认为"提示"
- footer?: null, // 对话框的页脚,默认为null
- visible: boolean, // 对话框是否可见
- confirmLoading?: boolean, // 确认按钮是否处于加载状态,默认为false
- destroyOnClose?: boolean, // 对话框关闭时是否销毁组件,默认为false
- maskClosable?: boolean, // 点击遮罩层是否可关闭对话框,默认为false
- centered?: boolean, // 对话框是否居中显示,默认为false
- }
- // 设置props的默认值
- const props = withDefaults(defineProps<Props>(), { title: '摄像头信息', visible: false, destroyOnClose: false, maskClosable: true })
- // 创建ref引用modalTitleRef,用于引用组件中的标题元素
- const modalTitleRef = ref<HTMLElement | null | any>(null);
- // 使用useDraggable钩子,获取拖拽相关属性
- const { x, y, isDragging } = useDraggable(modalTitleRef);
- // 创建emit函数,用于触发自定义事件
- const emit = defineEmits(['ok', 'update:visible', 'cancel'])
- // 处理ok事件的函数
- const handleOk = (e: MouseEvent) => {
- emit('ok')
- };
- // 处理cancel事件的函数
- const handleCancel = () => {
- emit('update:visible', false)
- emit('cancel')
- }
- // 创建各种响应式数据
- const startX = ref<number>(0); // 记录起始点的 x 坐标
- const startY = ref<number>(0); // 记录起始点的 y 坐标
- const startedDrag = ref(false); // 标志位,表示是否开始拖拽,默认为 false
- const transformX = ref(0); // x 偏移量
- const transformY = ref(0); // y 偏移量
- const preTransformX = ref(0); // 拖拽前的 x 偏移量
- const preTransformY = ref(0); // 拖拽前的 y 偏移量
- const dragRect = ref({ left: 0, right: 0, top: 0, bottom: 0 }); // 可拖拽的边界
- // 监听x和y的变化
- watch([x, y], () => { // 监听鼠标移动事件的函数
- if (!startedDrag.value) { // 如果尚未开始拖拽
- startX.value = x.value; // 记录起始点的 x 坐标
- startY.value = y.value; // 记录起始点的 y 坐标
- const bodyRect = document.body.getBoundingClientRect(); // 获取页面 body 元素的边界信息
- const titleRect = modalTitleRef.value.getBoundingClientRect(); // 获取 modalTitle 元素的边界信息
- dragRect.value.right = bodyRect.width - titleRect.width; // 计算可拖拽的最大右边界
- dragRect.value.bottom = bodyRect.height - titleRect.height; // 计算可拖拽的最大下边界
- preTransformX.value = transformX.value; // 记录拖拽前的 x 偏移量
- preTransformY.value = transformY.value; // 记录拖拽前的 y 偏移量
- }
- startedDrag.value = true; // 设置已开始拖拽标志
- });
- // 监听isDragging的变化
- watch(isDragging, () => { // 监听 isDragging 变量的改变
- if (!isDragging) { // 如果 isDragging 变为 false
- startedDrag.value = false; // 将 startedDrag.value 设置为 false,表示拖拽操作结束
- }
- });
- // 使用watchEffect监听响应式数据的变化
- watchEffect(() => { // 响应 startedDrag.value 的变化
- if (startedDrag.value) { // 如果 startedDrag.value 为 true,表示正在进行拖拽操作
- transformX.value = // 计算 x 偏移量
- preTransformX.value +
- Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) -
- startX.value;
- transformY.value = // 计算 y 偏移量
- preTransformY.value +
- Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) -
- startY.value;
- }
- });
- // 计算transformStyle,用于动态设置对话框的位置
- const transformStyle = computed<CSSProperties>(() => {
- return {
- transform: `translate(${transformX.value}px, ${transformY.value}px)`,
- };
- });
- </script>
|