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
相关产品推荐
相关产品推荐

