191 lines
4.7 KiB
TypeScript
191 lines
4.7 KiB
TypeScript
/**
|
||
* Modal Portal 工具函数
|
||
* 专门处理复杂容器结构中的 Modal 渲染问题
|
||
*/
|
||
|
||
/**
|
||
* 创建 Modal 容器并确保正确的层级
|
||
*/
|
||
export const createModalContainer = (id: string = 'modal-root'): HTMLElement => {
|
||
// 检查是否已存在容器
|
||
let container = document.getElementById(id);
|
||
|
||
if (!container) {
|
||
container = document.createElement('div');
|
||
container.id = id;
|
||
|
||
// 设置容器样式,确保不受任何父级影响
|
||
container.style.cssText = `
|
||
position: fixed;
|
||
top: 0;
|
||
left: 0;
|
||
right: 0;
|
||
bottom: 0;
|
||
pointer-events: none;
|
||
z-index: 999999;
|
||
isolation: isolate;
|
||
`;
|
||
|
||
// 直接添加到 body,避免复杂容器结构的影响
|
||
document.body.appendChild(container);
|
||
}
|
||
|
||
return container;
|
||
};
|
||
|
||
/**
|
||
* 清理 Modal 容器
|
||
*/
|
||
export const cleanupModalContainer = (id: string = 'modal-root'): void => {
|
||
const container = document.getElementById(id);
|
||
if (container && container.children.length === 0) {
|
||
document.body.removeChild(container);
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 检测当前环境是否有复杂的容器结构
|
||
*/
|
||
export const detectComplexContainerStructure = (element?: HTMLElement): boolean => {
|
||
const targetElement = element || document.querySelector('[class*="h-screen"]') as HTMLElement;
|
||
|
||
if (!targetElement) return false;
|
||
|
||
const indicators = [
|
||
'h-screen',
|
||
'flex-col',
|
||
'overflow-y-auto',
|
||
'overflow-auto',
|
||
'overflow-scroll'
|
||
];
|
||
|
||
// 检查是否包含复杂容器结构的指示器
|
||
const hasComplexStructure = indicators.some(indicator =>
|
||
document.querySelector(`[class*="${indicator}"]`)
|
||
);
|
||
|
||
if (hasComplexStructure) {
|
||
console.log('Complex container structure detected in DOM');
|
||
}
|
||
|
||
return hasComplexStructure;
|
||
};
|
||
|
||
/**
|
||
* 应用复杂容器结构的修复
|
||
*/
|
||
export const applyComplexContainerFix = (modalElement: HTMLElement): void => {
|
||
if (!modalElement) return;
|
||
|
||
// 添加修复类
|
||
modalElement.classList.add('complex-container-fix');
|
||
modalElement.setAttribute('data-complex-container', 'true');
|
||
|
||
// 强制样式修复
|
||
const fixStyles = {
|
||
position: 'fixed',
|
||
top: '0',
|
||
left: '0',
|
||
right: '0',
|
||
bottom: '0',
|
||
width: '100vw',
|
||
height: '100vh',
|
||
zIndex: '999999',
|
||
transform: 'translateZ(0)',
|
||
isolation: 'isolate',
|
||
contain: 'none',
|
||
clipPath: 'none',
|
||
clip: 'auto'
|
||
};
|
||
|
||
Object.assign(modalElement.style, fixStyles);
|
||
|
||
// 修复背景遮罩
|
||
const backdrop = modalElement.querySelector('.modal-backdrop-fixed') as HTMLElement;
|
||
if (backdrop) {
|
||
const backdropStyles = {
|
||
position: 'fixed',
|
||
top: '0',
|
||
left: '0',
|
||
right: '0',
|
||
bottom: '0',
|
||
width: '100vw',
|
||
height: '100vh',
|
||
zIndex: '-1'
|
||
};
|
||
|
||
Object.assign(backdrop.style, backdropStyles);
|
||
}
|
||
|
||
console.log('Applied complex container fix to modal');
|
||
};
|
||
|
||
/**
|
||
* 移除复杂容器结构的修复
|
||
*/
|
||
export const removeComplexContainerFix = (modalElement: HTMLElement): void => {
|
||
if (!modalElement) return;
|
||
|
||
modalElement.classList.remove('complex-container-fix');
|
||
modalElement.removeAttribute('data-complex-container');
|
||
|
||
// 重置样式(让 CSS 类接管)
|
||
const stylesToReset = [
|
||
'position', 'top', 'left', 'right', 'bottom',
|
||
'width', 'height', 'zIndex', 'transform',
|
||
'isolation', 'contain', 'clipPath', 'clip'
|
||
];
|
||
|
||
stylesToReset.forEach(prop => {
|
||
modalElement.style.removeProperty(prop);
|
||
});
|
||
|
||
const backdrop = modalElement.querySelector('.modal-backdrop-fixed') as HTMLElement;
|
||
if (backdrop) {
|
||
stylesToReset.forEach(prop => {
|
||
backdrop.style.removeProperty(prop);
|
||
});
|
||
}
|
||
};
|
||
|
||
/**
|
||
* 获取安全的 Modal 渲染容器
|
||
* 确保 Modal 始终渲染在正确的位置
|
||
*/
|
||
export const getSafeModalContainer = (): HTMLElement => {
|
||
// 优先使用专门的 modal 容器
|
||
let container = document.getElementById('modal-root');
|
||
|
||
if (!container) {
|
||
container = createModalContainer('modal-root');
|
||
}
|
||
|
||
// 确保容器在 body 的最后,避免被其他元素覆盖
|
||
if (container.parentElement === document.body) {
|
||
document.body.appendChild(container);
|
||
}
|
||
|
||
return container;
|
||
};
|
||
|
||
/**
|
||
* 监听窗口大小变化,确保 Modal 始终正确覆盖
|
||
*/
|
||
export const setupModalResizeHandler = (modalElement: HTMLElement): (() => void) => {
|
||
const handleResize = () => {
|
||
if (modalElement.hasAttribute('data-complex-container')) {
|
||
// 重新应用修复
|
||
applyComplexContainerFix(modalElement);
|
||
}
|
||
};
|
||
|
||
window.addEventListener('resize', handleResize);
|
||
window.addEventListener('orientationchange', handleResize);
|
||
|
||
// 返回清理函数
|
||
return () => {
|
||
window.removeEventListener('resize', handleResize);
|
||
window.removeEventListener('orientationchange', handleResize);
|
||
};
|
||
};
|