-
-
Notifications
You must be signed in to change notification settings - Fork 3.9k
Closed as not planned
Labels
Description
Version
4.2.6
Environment
win11, edge版本 140.0.3485.81 (正式版本) (64 位)、 vue3.4.27、vite 5.2.1
Steps to reproduce
目录结构 components --dragable-modal.vue views -- pageA.vue -- pageB.vue
分隔
dragable-modal.vue
目录结构
components
--dragable-modal.vue
views
-- pageA.vue
-- pageB.vue
分隔
dragable-modal.vue
<template>
<a-modal ref="modalRef" v-model:open="visible" :wrap-style="{ overflow: 'hidden' }" :mask-closable="false" :mask="mask" :keyboard="false" :closable="closable" :class="isFull?'full-modal':'draggle-modal'" :width="width" wrap-class-name="custom-modal" @cancel="cancel" :destroyOnClose="destroyOnClose" :maskClosable="maskClosable">
<template #title>
<div ref="modalTitleRef" class="title">{{ title }}</div>
<div class="full-screen" v-if="hasFull">
<FullscreenOutlined v-show="!isFull" @click="isFull=true"/>
<FullscreenExitOutlined v-show="isFull" @click="isFull=false"/>
</div> </template>
<template #modalRender="{ originVNode }">
<div class="modal-content" :style="transformStyle">
<component :is="originVNode"/>
</div>
</template>
<div v-if="type=='img'" class="content-box">
<slot></slot>
</div>
<div v-else>
<slot></slot>
</div>
<template #footer v-if="type!='img'">
<slot name="footer"></slot>
</template>
</a-modal>
</template>
<script setup>
import {computed, nextTick, onUnmounted, ref, watch, watchEffect} from "vue";
import {useDraggable} from '@vueuse/core';
const emit = defineEmits(['cancel']);
const props = defineProps({
title: { // 弹窗标题
type: String,
default: "预览",
},
open: { // 弹窗是否显示
type: Boolean,
default: false,
},
hasFull: { // 是否含有全屏功能
type: Boolean,
default: true
},
width: { // 弹窗宽度
type: Number,
default: 600,
},
// height: { // 弹窗高度
// type: Number,
// default: 'auto',
// },
mask: { // 弹窗是否显示遮罩
type: Boolean,
default: true,
},
destroyOnClose: {
type: Boolean,
default: true
},
maskClosable: {
type: Boolean,
default: true
},
type: { // 弹窗类型,分普通和img
type: String,
default: 'info'
},
footer: {
type: Object,
default: undefined,
},
closable: {
type: Boolean,
default: true
} });
const visible = ref(false); // 弹窗是否显示
const modalTitleRef = ref(null); // 标题
const isFull = ref(false); // 是否全屏
const {x, y, isDragging} = useDraggable(modalTitleRef);
const startX = ref(0); // 开始位置
x const startY = ref(0); // 开始位置
y const startedDrag = ref(false); // 是否开始拖拽
const bodyRect = document.body.getBoundingClientRect();
const defaultX = props.type == 'img' ? ((bodyRect.width - props.width) / 2 - 150) : 0; const transformX = ref(defaultX); // 当前偏移位置
x const transformY = ref(0); // 当前偏移位置
y const preTransformX = ref(0); // 上一次偏移位置
x const preTransformY = ref(0); // 上一次偏移位置 y
// 初始化弹框
const initModal = (val) => {
visible.value = val;
};
watch(() => props.open, (val) => {
initModal(val) }, {immediate: true})
// 定义拖拽区域边界
const dragRect = ref({
left: 0, // 左边界
right: 0, // 右边界
top: 0, // 上边界
bottom: 0, // 下边界
});
// 监听拖拽位置
watch([x, y], () => {
if (!isFull.value) {
if (!startedDrag.value) {
startX.value = x.value;
startY.value = y.value;
const bodyRect = document.body.getBoundingClientRect();
const titleRect = modalTitleRef.value.getBoundingClientRect();
dragRect.value.right = bodyRect.width - titleRect.width;
dragRect.value.bottom = bodyRect.height - titleRect.height;
preTransformX.value = transformX.value;
preTransformY.value = transformY.value;
}
startedDrag.value = true;
}
});
// 监听拖拽状态
watch(isDragging, () => {
if (!isDragging) {
startedDrag.value = false;
} });
// 监听拖拽偏移
watchEffect(() => {
if (startedDrag.value) {
transformX.value = preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value; transformY.value = preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value;
}
});
// 拖拽偏移样式
const transformStyle = computed(() => {
return {
transform: `translate(${transformX.value}px, ${transformY.value}px)`,
};
});
// 全屏切换
watch(isFull, (val) => {
if (val) {
transformX.value = 0;
transformY.value = 0;
startedDrag.value = false;
} else {
nextTick(() => {
if (preTransformX.value === 0 && preTransformY.value === 0) {
transformX.value = defaultX;
} else {
transformX.value = preTransformX.value + Math.min(Math.max(dragRect.value.left, x.value), dragRect.value.right) - startX.value;
transformY.value = preTransformY.value + Math.min(Math.max(dragRect.value.top, y.value), dragRect.value.bottom) - startY.value;
}
});
}
})
function cancel() {
emit('cancel');
}
</script>
<style lang="less">
.ant-modal-wrap {
&.custom-modal {
pointer-events: none;
.ant-modal {
padding-bottom: 0;
.modal-content {
width: 100%;
height: 100%;
pointer-events: auto;
}
.ant-modal-content {
width: 100%;
height: 100%;
padding: 0;
border-radius: 4px;
overflow: hidden;
.ant-modal-header {
margin-bottom: 0;
cursor: move;
border-bottom: 1px solid #f4f4f4;
.title {
padding: 5px 15px;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
width: calc(100% - 60px);
}
.full-screen {
position: absolute;
top: 6px;
right: 45px;
padding: 0 5px;
}
}
.ant-modal-close {
top: 7px;
}
.ant-modal-body {
height: calc(100% - 34px);
padding: 0 10px;
.content-box {
height: 100%
}
}
}
&.full-modal {
width: 100% !important;
height: 100% !important;
max-width: 100%;
top: 0;
left: 0;
padding-bottom: 0;
margin: 0;
.modal-content {
.ant-modal-content {
.ant-modal-header {
cursor: default;
}
}
}
}
&.modal-form-box, &.smart-approve-modal {
.ant-modal-content {
padding: 5px 15px 15px;
.ant-modal-title {
.title {
padding-left: 0;
}
}
.ant-modal-body {
padding: 10px 5px 0px;
height: auto;
max-height: 70vh;
overflow-y: auto;
}
}
}
}
}
}
</style>
pageA.vue
<template>
<a-button @click="openPageB">openPageB</a-button>
</template>
<script setup >
function openPageB() {
router.push('/pageB')
}
</script>
pageB.vue
<template>
<dragbale-modal :open="open" >
<p>我是弹框</p>
</dragbale-modal>
</template>
<script setup >
const open = ref(false);
onMounted(() => {
open.value=true;
})
</script>
a页面点击按钮跳转B页面后,会弹出弹框, 此时点击浏览器回退按钮页面回退至A页面但弹框仍然显示
What is expected?
点击浏览器回退按钮页面回退至A页面弹框关闭
What is actually happening?
点击浏览器回退按钮页面回退至A页面但弹框仍然显示