React中实现数组filter筛选切换的淡入淡出过渡动画方案
分类切换淡入淡出效果实现
你之前用React Transition Group没生效,基本都是key设置错误、包裹层级不对、动画时长不匹配这几个原因,下面给两种可直接落地的实现方案:
方案1:React Transition Group 实现(支持单项目独立动画)
- 先确保依赖安装完成
npm i react-transition-group # TS项目额外安装类型定义 npm i -D @types/react-transition-group
- 修改
ProjectsUl组件,用TransitionGroup和CSSTransition包裹列表项,注意每个项必须绑定唯一key,不能用数组下标:
import { FC, useEffect, useState } from 'react'; import { TransitionGroup, CSSTransition } from 'react-transition-group'; // 其余原有导入(ProjectsUlStyle、ProjectsLi、projects、IProject类型等)保持不变 export const ProjectsUl: FC<IProps> = ({ filter }) => { const [filtered, setFiltered] = useState<IProject[]>([]) useEffect(() => { const filteredProjects = projects.filter((i) => i.category.includes(filter)); setFiltered(filteredProjects); }, [filter]); return ( <ProjectsUlStyle> {/* component={null} 表示TransitionGroup不渲染额外的DOM节点 */} <TransitionGroup component={null}> {filtered.map((item) => ( <CSSTransition key={item.name} // 用项目名当唯一key,不要用数组index timeout={300} // 时长和CSS动画时长保持一致 classNames="fade" unmountOnExit // 筛选移除的项直接卸载DOM,避免占位 > <ProjectsLi filtered={item} /> </CSSTransition> ))} </TransitionGroup> </ProjectsUlStyle> ); };
- 添加对应过渡样式,全局CSS或styled-components内编写均可:
/* 进入初始态、离开结束态 */ .fade-enter, .fade-exit-to { opacity: 0; transform: translateY(6px); /* 不需要位移效果直接删掉这行 */ } /* 进入动画执行阶段、离开初始态 */ .fade-enter-active, .fade-exit { opacity: 1; transform: translateY(0); transition: all 300ms ease; } /* 动画完成稳定态 */ .fade-enter-done { opacity: 1; transform: translateY(0); }
几个容易踩的坑:
timeout数值必须和CSS里transition的时长完全一致,否则会出现动画截断、元素显隐时机错乱- 不要手动给
CSSTransition加in属性,TransitionGroup会自动管理子项的in状态 - 如果项目名可能重复,建议给每个项目加单独的唯一id字段当key
方案2:纯CSS实现(无额外依赖,代码量极小)
如果不需要单个项目的独立进出动画,只是要整体切换的淡入效果,完全不用额外装库,几行代码就能搞定:
- 修改
ProjectsUl组件,给列表容器绑定和当前筛选值关联的key,切换筛选时React会重新挂载容器触发动画:
export const ProjectsUl: FC<IProps> = ({ filter }) => { const [filtered, setFiltered] = useState<IProject[]>([]) useEffect(() => { const filteredProjects = projects.filter((i) => i.category.includes(filter)); setFiltered(filteredProjects); }, [filter]); return ( <ProjectsUlStyle key={filter} className="project-list-fade"> {filtered.map((item) => ( <ProjectsLi filtered={item} key={item.name} /> ))} </ProjectsUlStyle> ); };
- 添加CSS动画:
.project-list-fade { animation: listFadeIn 300ms ease forwards; } @keyframes listFadeIn { from { opacity: 0; } to { opacity: 1; } }
这个方案的效果是切换分类时整个列表整体淡入,实现成本最低,满足绝大多数简单场景的需求。
内容的提问来源于stack exchange,提问作者gpmotta21
相关产品推荐
相关产品推荐

