
本文介绍如何通过 css opacity 过渡与状态协调控制,实现卡片列表与单张选中卡片之间的平滑淡入淡出效果,避免 dom 完全替换导致的动画中断问题。
本文介绍如何通过 css opacity 过渡与状态协调控制,实现卡片列表与单张选中卡片之间的平滑淡入淡出效果,避免 dom 完全替换导致的动画中断问题。
在 React 中实现卡片选择态的视觉过渡,关键在于保持 DOM 结构稳定,而非条件渲染({condition ? : })导致元素频繁挂载/卸载——这会使 CSS transition 失效,因为浏览器无法对“不存在的元素”执行渐变动画。
✅ 推荐方案:统一容器 + 状态驱动透明度
将所有卡片(列表模式)和选中卡片(详情模式)保留在同一 DOM 容器中,通过 opacity 和 pointer-events 配合 transition 控制可见性与交互,而非 display: none 或条件移除节点。
Orderly React SDK 钩子使用参考指南,包括 useOrderEntry、usePositionStream、useOrderbookStream、useCollateral 等。
核心思路
- 始终渲染
(含全部卡片)和 (当前选中卡片)- 使用 opacity + transition 实现淡入淡出
- 用 pointer-events: none 暂时禁用非活跃区域的点击,防止误触
- 利用 useEffect 清理可能残留的 setTimeout,确保组件卸载安全
示例代码(优化后的组件结构)
const App = () => { const [selectedServiceIndex, setSelectedServiceIndex] = useState(null); const [isServiceSelected, setIsServiceSelected] = useState(false); const [isTransitioning, setIsTransitioning] = useState(false); // 控制过渡阶段 const handleServiceClick = (index) => { if (index = services_data.length) return; if (isServiceSelected && selectedServiceIndex === index) { // 取消选中:先淡出,再隐藏 setIsTransitioning(true); setTimeout(() => { setIsServiceSelected(false); setIsTransitioning(false); }, 300); } else { // 切换选中:先淡出当前视图,再更新索引并淡入 setIsTransitioning(true); setTimeout(() => { setSelectedServiceIndex(index); setIsServiceSelected(true); setIsTransitioning(false); }, 300); } }; const services = services_data.map((item, index) => ( <div key="{index}" onclick="{()"> handleServiceClick(index)}> <service name="{item.name}" imagename="{item.imageName}" classname="{item.className}" desc="{item.desc}"></service> </div> )); return ( <main> {/* 始终存在 —— 列表视图(默认显示,选中时淡出) */} <section classname="section services-section" id="services" style="{{" opacity: isserviceselected : pointerevents: transition: ease pointer-events step-end><div classname="container"> <div classname="row"> <div classname="page-header"> <div classname="section-title"> <h2>Services</h2> <p>Enhance efficiency, reliability, and quality with automated test solutions.</p> </div> </div> </div> <div classname="row services-row">{services}</div> </div> </section> {/* 始终存在 —— 详情视图(默认隐藏,选中时淡入) */} <div classname="selected-service" style="{{" opacity: isserviceselected : pointerevents: transition: ease pointer-events step-end transform willchange:> {isServiceSelected && selectedServiceIndex !== null && services[selectedServiceIndex]} </div> </main> ); };? 关键注意事项
- 不要用 display: none:它会触发重排(reflow),且无法过渡;opacity 是可过渡属性。
- pointer-events: none 的时机很重要:配合 transition 的 step-end 时间函数,确保在 opacity=0 时才禁用交互,避免点击穿透。
- will-change: 'opacity':提示浏览器对该属性做优化(尤其在复杂页面中提升动画流畅度)。
- 清理副作用:若使用 useEffect + setTimeout,务必在 useEffect 清理函数中调用 clearTimeout,防止内存泄漏或状态更新到已卸载组件。
- 可扩展性建议:如需更复杂的交互动画(如缩放、位移),可结合 react-transition-group 或 framer-motion,但本方案纯 CSS + React state 即可满足基础需求。
该方案兼顾简洁性、可维护性与用户体验——既保留了语义清晰的 DOM 结构,又实现了专业级的视觉反馈,是 React 卡片切换场景下的稳健实践。










