抽屉缩放动画后Tooltip位置未更新的问题求助
抽屉缩放后Tooltip未跟随/隐藏的解决方案
问题描述
我有一个可通过点击按钮调整大小的Drawer(抽屉),按钮带有Tooltip提示框。点击按钮触发抽屉缩放动画后,Tooltip停留在原位置,不会随按钮新位置调整。期望Tooltip要么跟随按钮移动,要么直接隐藏,而不是停在屏幕中间。尝试过通过onClick事件隐藏Tooltip但无效,需要在动画完成后触发处理逻辑。
核心原因
MUI的Tooltip默认基于触发元素的初始位置渲染,抽屉动画过程中元素位置变化时,Tooltip不会自动重新计算位置。直接在onClick中隐藏会因为动画尚未完成,Tooltip的状态无法同步更新。
解决方法
推荐通过监听抽屉动画结束事件来控制Tooltip的显示状态,实现点击时隐藏、动画完成后恢复的效果,步骤如下:
1. 给Sidebar添加动画结束回调
修改Sidebar组件,为Drawer的Paper元素绑定onTransitionEnd事件,通知父组件动画完成:
// Sidebar.tsx import {CSSObject, styled, Theme} from "@mui/material/styles"; import MuiDrawer from "@mui/material/Drawer"; import React from "react"; const drawerWidth = 260; const openedMixin = (theme: Theme): CSSObject => ({ width: drawerWidth, transition: theme.transitions.create('width', { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.enteringScreen, }), overflowX: 'hidden', }); const closedMixin = (theme: Theme): CSSObject => ({ transition: theme.transitions.create('width', { easing: theme.transitions.easing.sharp, duration: theme.transitions.duration.leavingScreen, }), overflowX: 'hidden', width: `calc(${theme.spacing(7)} + 1px)`, [theme.breakpoints.up('sm')]: { width: `calc(${theme.spacing(8)} + 1px)`, }, }); const Drawer = styled(MuiDrawer, {shouldForwardProp: (prop) => prop !== 'open'})( ({theme, open}) => ({ width: drawerWidth, flexShrink: 0, whiteSpace: 'nowrap', boxSizing: 'border-box', ...(open && { ...openedMixin(theme), '& .MuiDrawer-paper': openedMixin(theme), }), ...(!open && { ...closedMixin(theme), '& .MuiDrawer-paper': closedMixin(theme), }), }), ); type Props = { open: boolean, children: any, onTransitionEnd?: () => void } const Sidebar = ({open, children, onTransitionEnd}: Props) => { return ( <Drawer variant="permanent" open={open} PaperProps={{ elevation: 2, onTransitionEnd: onTransitionEnd }} > {children} </Drawer> ) } export default Sidebar;
2. 父组件管理Tooltip状态
在Sidebar的父组件中,添加状态控制Tooltip的显示,点击抽屉按钮时先隐藏Tooltip,动画结束后恢复:
// 父组件示例 import { useState } from 'react'; import Sidebar from './Sidebar'; import SidebarFooter from './SidebarFooter'; const ParentComponent = () => { const [drawerOpen, setDrawerOpen] = useState(true); const [tooltipVisible, setTooltipVisible] = useState(true); const toggleDrawer = () => { setDrawerOpen(!drawerOpen); setTooltipVisible(false); }; const handleDrawerTransitionEnd = () => { setTooltipVisible(true); }; return ( <div> <Sidebar open={drawerOpen} onTransitionEnd={handleDrawerTransitionEnd}> {/* 侧边栏其他内容 */} <SidebarFooter open={drawerOpen} toggleDrawer={toggleDrawer} tooltipVisible={tooltipVisible} /> </Sidebar> </div> ); }; export default ParentComponent;
3. 更新CustomTooltip和SidebarFooter
修改CustomTooltip,通过open属性控制显示状态;SidebarFooter传入该状态:
// CustomTooltip.tsx import {Tooltip} from "@mui/material"; type Props = { title: string, placement?: 'bottom-end' | 'bottom-start' | 'bottom' | 'left-end' | 'left-start' | 'left' | 'right-end' | 'right-start' | 'right' | 'top-end' | 'top-start' | 'top', open?: boolean, children: any } const CustomTooltip = ({title, children, placement = 'right', open = true}: Props) => { return ( <Tooltip arrow title={title} placement={placement} open={open} > {children} </Tooltip> ) } export default CustomTooltip;
// SidebarFooter.tsx import { IconButton } from '@mui/material'; import ChevronLeftIcon from '@mui/icons-material/ChevronLeft'; import ChevronRightIcon from '@mui/icons-material/ChevronRight'; import CustomTooltip from './CustomTooltip'; type Props = { open: boolean, toggleDrawer: () => void, tooltipVisible: boolean } const SidebarFooter = ({open, toggleDrawer, tooltipVisible}: Props) => { return ( <CustomTooltip title={open ? '隐藏' : '展开'} open={tooltipVisible} > <div className={iconStyle}> <IconButton onClick={toggleDrawer}> {open ? <ChevronLeftIcon/> : <ChevronRightIcon/>} </IconButton> </div> </CustomTooltip> ) } export default SidebarFooter;
可选方案:让Tooltip自动跟随
如果希望Tooltip跟随按钮移动,可以基于MUI的Popper组件自定义Tooltip的定位逻辑,但实现复杂度较高,上述隐藏/恢复方案更简单直接,符合需求。
内容的提问来源于stack exchange,提问作者Noah13
相关产品推荐
相关产品推荐

