You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现Material-UI Dialog从点击图片处过渡展开?

实现Material-UI Dialog从图片位置展开并过渡尺寸

核心思路

要实现这个效果,咱们需要两步关键操作:

  1. 精准获取触发图片在屏幕上的位置和尺寸,以此作为Dialog展开的原点和初始大小
  2. 结合Grow过渡组件和自定义样式,让Dialog从图片的位置/尺寸平滑过渡到目标状态

步骤1:获取图片的屏幕坐标与尺寸

首先给触发图片加个ref,这样在Dialog打开时能拿到它的位置信息:

// 父组件中管理图片引用和Dialog状态
class ParentComponent extends Component {
  imageRef = React.createRef();
  state = {
    previewImage: false,
    imgOrigin: '',
    imgSize: { width: 0, height: 0 }
  };

  openDialog = () => {
    const imgRect = this.imageRef.current.getBoundingClientRect();
    // 计算图片中心点作为展开原点,也可以改成左上角/右下角等
    const origin = `${imgRect.left + imgRect.width/2}px ${imgRect.top + imgRect.height/2}px`;
    this.setState({
      previewImage: true,
      imgOrigin: origin,
      imgSize: { width: imgRect.width, height: imgRect.height }
    });
  };

  render() {
    return (
      <>
        <img 
          ref={this.imageRef} 
          src="your-image-url" 
          onClick={this.openDialog} 
          style={{ cursor: 'pointer' }}
        />
        <ImagePopup 
          previewImage={this.state.previewImage} 
          close={() => this.setState({ previewImage: false })}
          imgOrigin={this.state.imgOrigin}
          imgSize={this.state.imgSize}
        />
      </>
    );
  }
}

步骤2:修改Dialog的过渡与样式

接下来调整ImagePopup组件,让它用获取到的原点和初始尺寸实现过渡:

class ImagePopup extends Component {
  popupTransition(props) {
    return (
      <Grow
        {...props}
        style={{ transformOrigin: this.props.imgOrigin }}
        timeout={500}
      />
    );
  }

  render() {
    const { imgSize, previewImage } = this.props;
    return (
      <Dialog
        TransitionComponent={this.popupTransition.bind(this)}
        onClose={this.props.close}
        open={previewImage}
        // 自定义Paper的样式,实现尺寸过渡
        PaperProps={{
          style: {
            position: 'fixed',
            left: '50%',
            top: '50%',
            transform: 'translate(-50%, -50%)',
            minWidth: 'auto',
            // 初始尺寸和图片一致,展开后过渡到目标大小
            width: previewImage ? '80vw' : imgSize.width,
            height: previewImage ? '80vh' : imgSize.height,
            transition: 'width 0.5s ease, height 0.5s ease'
          }
        }}
        maxWidth="lg"
        fullWidth
      >
        <DialogTitle id="alert-dialog-title">{"图片预览"}</DialogTitle>
        <DialogContent style={{ height: 'calc(100% - 64px)' }}>
          <img 
            src="your-large-image-url" 
            style={{ width: '100%', height: '100%', objectFit: 'contain' }} 
          />
        </DialogContent>
      </Dialog>
    );
  }
}

关键细节说明

  • transformOrigin:通过父组件传递的图片原点,让Grow组件以图片位置为中心展开
  • 尺寸过渡:给Dialog的Paper设置初始尺寸(和图片一致),打开时自动过渡到目标尺寸(80vw/80vh),配合Grow的缩放效果,实现完整的展开动画
  • 定位处理:用position: fixed和translate(-50%, -50%)确保Dialog从图片位置平滑移动到屏幕中心

函数组件版优化(可选)

如果习惯用函数组件,结合useRef和useEffect会更简洁:

function ImagePopup({ previewImage, close, imgOrigin, imgSize }) {
  const popupTransition = (props) => (
    <Grow {...props} style={{ transformOrigin: imgOrigin }} timeout={500} />
  );

  return (
    <Dialog
      TransitionComponent={popupTransition}
      onClose={close}
      open={previewImage}
      PaperProps={{
        style: {
          position: 'fixed',
          left: '50%',
          top: '50%',
          transform: 'translate(-50%, -50%)',
          minWidth: 'auto',
          width: previewImage ? '80vw' : imgSize.width,
          height: previewImage ? '80vh' : imgSize.height,
          transition: 'width 0.5s ease, height 0.5s ease'
        }
      }}
      maxWidth="lg"
      fullWidth
    >
      <DialogTitle>图片预览</DialogTitle>
      <DialogContent style={{ height: 'calc(100% - 64px)' }}>
        <img src="your-large-image-url" style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
      </DialogContent>
    </Dialog>
  );
}

内容的提问来源于stack exchange,提问作者meds

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 07:05:18