Container 布局容器中对el-main中的弹窗限制
·
环境:vue3+elementPlus
原因:使用el-dialog时,遮罩和拖动范围都是全屏的,此时想要切换为其他菜单页面时无法做到,只能关闭弹窗才能切换
解决方法(不改源码):
1.先将弹窗的属性append-to-body改为true
2.修改css
.el-overlay,.el-overlay-dialog{
position: absolute !important;
}
做到以上步骤已经将遮罩和弹窗限制在el-main中,可以在弹窗打开期间使用el-main区域外的其他功能了,但是弹窗的拖动范围还是全屏或者说错误的。
3.创建限制拖动范围文件dialogDragLimit.js
// 弹窗拖动范围限制工具
/**
* 获取当前激活的el-main容器
* @returns {HTMLElement|null} - 当前可见的el-main元素
*/
const getActiveElMain = () => {
// 查找所有的el-main元素
const elMainElements = document.querySelectorAll('.el-main');
// 找到可见的el-main元素
for (const elMain of elMainElements) {
const style = window.getComputedStyle(elMain);
if (style.display !== 'none' && style.visibility !== 'hidden') {
return elMain;
}
}
return null;
};
/**
* 限制弹窗拖动范围在el-main内
* @param {HTMLElement} dialogElement - 弹窗元素
*/
const limitDialogDragToElMain = (dialogElement) => {
if (!dialogElement) return;
// 监听弹窗的mousedown事件,准备限制拖动
const headerElement = dialogElement.querySelector('.el-dialog__header');
if (!headerElement) return;
headerElement.addEventListener('mousedown', (e) => {
const elMain = getActiveElMain();
if (!elMain) return;
// 计算el-main边界函数
const calculateElMainBounds = () => {
const elMainRect = elMain.getBoundingClientRect();
return {
left: elMainRect.left,
top: elMainRect.top,
right: elMainRect.right,
bottom: elMainRect.bottom
};
};
let elMainBounds = calculateElMainBounds();
// 计算可拖动范围(使用弹窗当前实际大小)
const calculateMaxBounds = () => {
const dialogRect = dialogElement.getBoundingClientRect();
const margin = 15; // 添加10px边距
return {
maxLeft: elMainBounds.right - dialogRect.width - margin,
maxTop: elMainBounds.bottom - dialogRect.height - margin,
minLeft: elMainBounds.left + margin,
minTop: elMainBounds.top + margin
};
};
let maxBounds = calculateMaxBounds();
// 获取当前的transform值,计算初始偏移
const getCurrentOffset = () => {
const currentTransform = dialogElement.style.transform;
if (currentTransform) {
const match = currentTransform.match(/translate\(([^,]+),\s*([^)]+)\)/);
if (match) {
return {
offsetX: parseFloat(match[1]),
offsetY: parseFloat(match[2])
};
}
}
return { offsetX: 0, offsetY: 0 };
};
const { offsetX, offsetY } = getCurrentOffset();
const downX = e.clientX;
const downY = e.clientY;
// 窗口大小变化时重新计算边界
const handleResize = () => {
elMainBounds = calculateElMainBounds();
maxBounds = calculateMaxBounds();
};
// 添加窗口大小变化监听
window.addEventListener('resize', handleResize);
const onMousemove = (e2) => {
// 计算新的偏移量
const newOffsetX = offsetX + (e2.clientX - downX);
const newOffsetY = offsetY + (e2.clientY - downY);
// 获取弹窗当前实际位置和大小
const dialogRect = dialogElement.getBoundingClientRect();
// 计算弹窗在应用新偏移后的绝对位置
// 注意:这里我们需要基于弹窗的原始位置(无transform)来计算
// 但由于transform的影响,我们需要重新计算
const currentTransform = dialogElement.style.transform;
let currentOffsetX = 0;
let currentOffsetY = 0;
if (currentTransform) {
const match = currentTransform.match(/translate\(([^,]+),\s*([^)]+)\)/);
if (match) {
currentOffsetX = parseFloat(match[1]);
currentOffsetY = parseFloat(match[2]);
}
}
// 计算弹窗的原始位置(无transform时的位置)
const originalLeft = dialogRect.left - currentOffsetX;
const originalTop = dialogRect.top - currentOffsetY;
// 计算新的绝对位置
const newDialogLeft = originalLeft + newOffsetX;
const newDialogTop = originalTop + newOffsetY;
// 重新计算限制边界(确保使用最新的弹窗大小)
maxBounds = calculateMaxBounds();
// 限制在el-main范围内(带边距)
let limitedOffsetX = newOffsetX;
let limitedOffsetY = newOffsetY;
// 左右限制
if (newDialogLeft < maxBounds.minLeft) {
limitedOffsetX = maxBounds.minLeft - originalLeft;
} else if (newDialogLeft > maxBounds.maxLeft) {
limitedOffsetX = maxBounds.maxLeft - originalLeft;
}
// 上下限制
if (newDialogTop < maxBounds.minTop) {
limitedOffsetY = maxBounds.minTop - originalTop;
} else if (newDialogTop > maxBounds.maxTop) {
limitedOffsetY = maxBounds.maxTop - originalTop;
}
// 更新弹窗位置
dialogElement.style.transform = `translate(${limitedOffsetX}px, ${limitedOffsetY}px)`;
};
const onMouseup = () => {
// 移除事件监听
document.removeEventListener('mousemove', onMousemove);
document.removeEventListener('mouseup', onMouseup);
window.removeEventListener('resize', handleResize);
};
document.addEventListener('mousemove', onMousemove);
document.addEventListener('mouseup', onMouseup);
});
};
/**
* 初始化弹窗拖动范围限制
*/
const initDialogDragLimit = () => {
// 监听DOM变化,为新创建的弹窗添加限制
const observer = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
mutation.addedNodes.forEach((node) => {
if (node.nodeType === 1) {
// 检查是否是弹窗元素
const dialogElements = node.querySelectorAll('.el-dialog');
dialogElements.forEach(limitDialogDragToElMain);
// 检查节点本身是否是弹窗
if (node.classList && node.classList.contains('el-dialog')) {
limitDialogDragToElMain(node);
}
}
});
});
});
// 开始观察body的变化
observer.observe(document.body, {
childList: true,
subtree: true
});
// 为已存在的弹窗添加限制
document.querySelectorAll('.el-dialog').forEach(limitDialogDragToElMain);
};
export {
limitDialogDragToElMain,
initDialogDragLimit
};
4.使用上述文件限制拖动范围
在App.vue的script中
import { initDialogDragLimit } from '@/utils/dialogDragLimit.js'
....
created(){
....
// 初始化弹窗拖动范围限制
initDialogDragLimit()
}
以上步骤完即可完成效果
更多推荐
所有评论(0)