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

React.js中用react-transition-group创建点击触发动画模态框及关闭问题解决

使用react-transition-group创建带动画的可关闭模态框

1. 安装依赖

首先安装所需库:

npm install react-transition-group

2. 基础实现:带动画的模态框

通过CSSTransition组件包裹模态框,配合CSS定义进入/退出动画,实现基础的触发式动画模态框。

组件代码

import { useState } from 'react';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';

function AnimatedModal() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  return (
    <div className="modal-container">
      {/* 触发按钮/链接 */}
      <button onClick={openModal} className="open-modal-btn">
        打开模态框
      </button>

      {/* 带过渡动画的模态框 */}
      <CSSTransition
        in={isModalOpen}
        timeout={300}
        classNames="modal"
        unmountOnExit
      >
        <div className="modal-backdrop">
          <div className="modal-content">
            <button onClick={closeModal} className="close-btn">×</button>
            <h2>动画模态框</h2>
            <p>这是一个带过渡动画的模态框示例</p>
          </div>
        </div>
      </CSSTransition>
    </div>
  );
}

export default AnimatedModal;

动画样式(Modal.css)

/* 背景遮罩层 */
.modal-backdrop {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  justify-content: center;
  align-items: center;
}

/* 模态框主体 */
.modal-content {
  background-color: white;
  padding: 2rem;
  border-radius: 8px;
  position: relative;
  width: 90%;
  max-width: 500px;
}

.close-btn {
  position: absolute;
  top: 1rem;
  right: 1rem;
  font-size: 1.5rem;
  border: none;
  background: transparent;
  cursor: pointer;
}

/* 透明度过渡动画 */
.modal-enter {
  opacity: 0;
}

.modal-enter-active {
  opacity: 1;
  transition: opacity 300ms ease-in-out;
}

.modal-exit {
  opacity: 1;
}

.modal-exit-active {
  opacity: 0;
  transition: opacity 300ms ease-in-out;
}

/* 模态框缩放动画(可选) */
.modal-content.modal-enter {
  transform: scale(0.8);
}

.modal-content.modal-enter-active {
  transform: scale(1);
  transition: transform 300ms ease-in-out;
}

.modal-content.modal-exit {
  transform: scale(1);
}

.modal-content.modal-exit-active {
  transform: scale(0.8);
  transition: transform 300ms ease-in-out;
}

3. 解决点击外部/ESC键关闭的问题

3.1 点击外部关闭

通过判断点击事件的target与currentTarget是否一致,仅在点击背景遮罩层时触发关闭:

<div 
  className="modal-backdrop"
  onClick={(e) => {
    // 仅点击遮罩层本身时关闭
    if (e.target === e.currentTarget) {
      closeModal();
    }
  }}
>
  {/* 模态框内容不变 */}
</div>

3.2 ESC键关闭

使用useEffect监听键盘事件,组件卸载时移除监听避免内存泄漏:

import { useState, useEffect } from 'react';
// 其余导入不变

function AnimatedModal() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  // 监听ESC键
  useEffect(() => {
    const handleEsc = (e) => {
      if (e.key === 'Escape' && isModalOpen) {
        closeModal();
      }
    };

    window.addEventListener('keydown', handleEsc);
    return () => window.removeEventListener('keydown', handleEsc);
  }, [isModalOpen]);

  // 其余代码不变
}

完整整合代码

import { useState, useEffect } from 'react';
import { CSSTransition } from 'react-transition-group';
import './Modal.css';

function AnimatedModal() {
  const [isModalOpen, setIsModalOpen] = useState(false);

  const openModal = () => setIsModalOpen(true);
  const closeModal = () => setIsModalOpen(false);

  // ESC键关闭逻辑
  useEffect(() => {
    const handleEsc = (e) => {
      if (e.key === 'Escape' && isModalOpen) {
        closeModal();
      }
    };

    window.addEventListener('keydown', handleEsc);
    return () => window.removeEventListener('keydown', handleEsc);
  }, [isModalOpen]);

  return (
    <div className="modal-container">
      <button onClick={openModal} className="open-modal-btn">
        打开模态框
      </button>

      <CSSTransition
        in={isModalOpen}
        timeout={300}
        classNames="modal"
        unmountOnExit
      >
        <div 
          className="modal-backdrop"
          onClick={(e) => e.target === e.currentTarget && closeModal()}
        >
          <div className="modal-content">
            <button onClick={closeModal} className="close-btn">×</button>
            <h2>动画模态框</h2>
            <p>支持点击外部关闭,也可以按ESC键关闭</p>
          </div>
        </div>
      </CSSTransition>
    </div>
  );
}

export default AnimatedModal;

关键说明

  • unmountOnExit属性会在退出动画完成后自动卸载模态框DOM,优化性能。
  • 点击外部关闭的核心是区分点击目标:仅点击遮罩层而非模态框内容时触发关闭。
  • ESC键监听需在组件卸载时移除,避免无用事件占用资源。

内容的提问来源于stack exchange,提问作者Kamal Shivji Bhadra

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 14:22:03