如何在父元素导航栏过渡动画结束后再渲染子搜索组件?
问题根源
点击展开按钮时你同步执行了两个操作:给导航栏添加expanded类触发1000ms的高度过渡、同时将isExpanded设为true直接渲染搜索框组件,二者执行时序不一致导致搜索框提前显示。
方案1:纯CSS实现(推荐)
无需修改核心JS逻辑,性能稳定无计时偏差,仅需调整两处代码:
- 移除JSX中对
expandedContainer的条件渲染,改为永久渲染:
// 把原来的条件渲染代码替换为下面这段 <div className="expandedContainer"> <ServiceSearchFields /> </div>
- 调整SCSS样式,给搜索框容器加显隐过渡,和导航栏展开时序对齐:
.expandedContainer { height: 100%; display: flex; flex-direction: column; justify-content: flex-start; align-items: center; gap: 15px; /* 新增以下4行 */ opacity: 0; visibility: hidden; /* 延迟0.8s触发显隐过渡,刚好导航快完成展开时显示搜索框 */ transition: opacity 0.2s ease 0.8s, visibility 0.2s ease 0.8s; } /* 导航展开后显示搜索框容器 */ .navWrapper.expanded .expandedContainer { opacity: 1; visibility: visible; } /* 关闭时搜索框立刻隐藏,无需延迟 */ .navWrapper:not(.expanded) .expandedContainer { transition: opacity 0.2s ease, visibility 0.2s ease; }
方案2:JS定时器控制渲染时序
如果你需要保留条件渲染的逻辑,可以用定时器和导航过渡时长对齐,修改JS代码如下:
import { useState, useRef, useEffect } from 'react'; const NavMobile = () => { const [isExpanded, setIsExpanded] = useState(false); const timerRef = useRef(null); const expandNav = () => { document.getElementById("nav")?.classList.add("expanded"); // 延迟1000ms(和过渡时长一致)再渲染搜索框 timerRef.current = setTimeout(() => { setIsExpanded(true); }, 1000); }; const closeNav = () => { // 先隐藏搜索框 setIsExpanded(false); // 延迟1000ms再收起导航 timerRef.current = setTimeout(() => { document.getElementById("nav")?.classList.remove("expanded"); }, 1000); }; // 组件卸载时清除定时器,避免内存泄漏 useEffect(() => { return () => clearTimeout(timerRef.current); }, []); return ( <div id="nav" className="navWrapper"> <nav className="container"> <button className="navButton" style={{ display: isExpanded ? "none" : undefined }} onClick={expandNav} > <i className="fa fa-search"></i> Search a service ... </button> {isExpanded ? ( <div className="expandedContainer"> <ServiceSearchFields /> </div> ) : null} </nav> </div> ); };
内容的提问来源于stack exchange,提问作者Gustavo Farias
相关产品推荐
相关产品推荐

