修复提示框的弹出位置移动的问题
This commit is contained in:
@@ -60,6 +60,9 @@ export function Tooltip({
|
||||
// 获取实际显示状态
|
||||
const isVisible = isControlled ? controlledVisible : visible;
|
||||
|
||||
// 添加一个状态来控制实际渲染,解决位置跳跃问题
|
||||
const [readyToShow, setReadyToShow] = useState(false);
|
||||
|
||||
// 引用DOM元素
|
||||
const triggerRef = useRef<HTMLDivElement>(null);
|
||||
const tooltipRef = useRef<HTMLDivElement>(null);
|
||||
@@ -73,11 +76,17 @@ export function Tooltip({
|
||||
if (!isControlled) {
|
||||
setVisible(newVisible);
|
||||
}
|
||||
onVisibleChange?.(newVisible);
|
||||
|
||||
// 当显示状态变为false时,重置actualPlacement为初始placement
|
||||
// 当显示状态变为false时,立即隐藏
|
||||
if (!newVisible) {
|
||||
setReadyToShow(false);
|
||||
onVisibleChange?.(newVisible);
|
||||
// 当显示状态变为false时,重置actualPlacement为初始placement
|
||||
setActualPlacement(placement);
|
||||
} else {
|
||||
// 当显示状态变为true时,先延迟设置readyToShow
|
||||
// 这样允许位置预计算完成后再显示tooltip
|
||||
onVisibleChange?.(newVisible);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -97,7 +106,6 @@ export function Tooltip({
|
||||
|
||||
// 获取触发元素位置
|
||||
const triggerRect = triggerRef.current.getBoundingClientRect();
|
||||
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
||||
|
||||
// 设置最大宽度
|
||||
tooltipRef.current.style.maxWidth = typeof maxWidth === 'number'
|
||||
@@ -115,6 +123,16 @@ export function Tooltip({
|
||||
tooltipRef.current.style.overflow = 'visible';
|
||||
}
|
||||
|
||||
// 强制重新计算布局,确保maxHeight生效后再获取尺寸
|
||||
tooltipRef.current.style.visibility = 'hidden';
|
||||
tooltipRef.current.style.display = 'block';
|
||||
|
||||
// 触发重排,确保maxHeight限制已应用
|
||||
void tooltipRef.current.offsetHeight;
|
||||
|
||||
// 获取应用maxHeight后的实际tooltip尺寸
|
||||
const tooltipRect = tooltipRef.current.getBoundingClientRect();
|
||||
|
||||
// 计算各个方向的位置
|
||||
let top = 0, left = 0;
|
||||
let arrowTop = 0, arrowLeft = 0;
|
||||
@@ -311,6 +329,17 @@ export function Tooltip({
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 恢复可见性(位置计算完成后)
|
||||
tooltipRef.current.style.visibility = 'visible';
|
||||
|
||||
// 如果位置已更新且还没有显示,现在可以显示了
|
||||
if (!readyToShow) {
|
||||
// 使用requestAnimationFrame确保DOM更新后再显示
|
||||
requestAnimationFrame(() => {
|
||||
setReadyToShow(true);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 当组件首次挂载或placement改变时,重置actualPlacement
|
||||
@@ -318,12 +347,27 @@ export function Tooltip({
|
||||
setActualPlacement(placement);
|
||||
}, [placement]);
|
||||
|
||||
// 计算提示框位置
|
||||
// 当isVisible状态变化时,处理初始化和清理工作
|
||||
useEffect(() => {
|
||||
if (!isVisible) return;
|
||||
if (!isVisible) {
|
||||
// 当tooltip隐藏时,重置readyToShow状态
|
||||
setReadyToShow(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// 初始化位置
|
||||
updateTooltipPosition();
|
||||
// 创建一个隐藏的tooltip用于预计算位置
|
||||
// 使用一个隐藏的div来渲染tooltip,并获取其尺寸
|
||||
const preCalculatePosition = () => {
|
||||
// 初始时先不显示,让updateTooltipPosition完成位置计算
|
||||
setReadyToShow(false);
|
||||
|
||||
// 初始化位置计算 - 添加短暂延迟确保内容已渲染
|
||||
setTimeout(() => {
|
||||
updateTooltipPosition();
|
||||
}, 10);
|
||||
};
|
||||
|
||||
preCalculatePosition();
|
||||
|
||||
// 添加滚动和调整大小事件监听器
|
||||
window.addEventListener('scroll', updateTooltipPosition, true);
|
||||
@@ -338,7 +382,7 @@ export function Tooltip({
|
||||
window.removeEventListener('resize', updateTooltipPosition);
|
||||
clearInterval(intervalId);
|
||||
};
|
||||
}, [isVisible, placement, maxWidth, showArrow, fixedPlacement, actualPlacement]);
|
||||
}, [isVisible, placement, maxWidth, showArrow, fixedPlacement]);
|
||||
|
||||
// 处理点击外部关闭
|
||||
useEffect(() => {
|
||||
@@ -389,18 +433,23 @@ export function Tooltip({
|
||||
`tooltip-${actualPlacement}`, // 使用actualPlacement而不是placement
|
||||
`tooltip-${theme}`,
|
||||
rich ? 'tooltip-rich' : '',
|
||||
isVisible ? 'tooltip-visible' : '',
|
||||
readyToShow ? 'tooltip-visible' : 'tooltip-hidden', // 使用readyToShow控制可见性
|
||||
fixedPlacement ? 'tooltip-fixed-placement' : '',
|
||||
className
|
||||
].filter(Boolean).join(' ');
|
||||
|
||||
// 使用Portal渲染提示框
|
||||
// 使用Portal渲染提示框,但根据readyToShow来控制可见性样式
|
||||
const tooltipPortal = isVisible && typeof document !== 'undefined'
|
||||
? createPortal(
|
||||
<div
|
||||
ref={tooltipRef}
|
||||
className={tooltipClassNames}
|
||||
style={{ maxWidth }}
|
||||
style={{
|
||||
maxWidth,
|
||||
opacity: readyToShow ? 1 : 0, // 根据readyToShow控制透明度
|
||||
visibility: readyToShow ? 'visible' : 'hidden', // 使用visibility确保在位置计算时元素存在但不可见
|
||||
transition: 'opacity 0.1s ease-out' // 添加平滑过渡效果
|
||||
}}
|
||||
>
|
||||
{renderTooltipContent()}
|
||||
{showArrow && <div className="tooltip-arrow"></div>}
|
||||
|
||||
Reference in New Issue
Block a user