React条件渲染子组件的面板高度动画实现咨询及react-spring可行性探讨
Hey there! Let's get that panel animation working for you. The core issue with your current code is that you're conditionally mounting/unmounting the content section—CSS transitions can't animate elements that are being added or removed from the DOM. Plus, we need explicit start/end values for properties like height to make transitions smooth. Let's cover two solid solutions:
Solution 1: CSS Transitions with React State
This approach keeps the content DOM element intact and uses React state to toggle its height, letting CSS handle the animation.
Step-by-Step Fix:
- Remove the conditional rendering of the content div—keep it in the DOM at all times.
- Use the
isOpenstate to control theheightandoverflowstyles of the content. - Add a CSS transition to the panel's content container for the
heightproperty.
Here's the updated code:
const { useState } = React; const Example = ({ title }) => { const [isOpen, setIsOpen] = useState(false); return ( <> <div style={{ position: "relative", width: "100%", height: "100%", backgroundColor: "tomato" }}></div> <div className="panel" style={{ position: "absolute", bottom: 20, right: 20, backgroundColor: "pink", width: 200, padding: 15 }}> <div>Title</div> <div onClick={() => setIsOpen(!isOpen)} style={{ cursor: "pointer" }}> {isOpen ? "Close" : "Open"} </div> {/* Keep content div in DOM, animate height */} <div className="panel-content" style={{ overflowY: isOpen ? "scroll" : "hidden", height: isOpen ? "250px" : "0", transition: "height 0.3s ease" }} > Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? </div> </div> </> ); }; // Fix the typo: ddocument → document ReactDOM.render( <Example title="Example using Hooks:" />, document.getElementById("react") );
html, body { width: 100%; height: 100%; } #react { width: 100%; height: 100%; }
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
Key Notes:
- We replaced the separate "Open"/"Close" elements with a single toggle button to clean up the code.
- The
panel-contentdiv always exists—we just toggle itsheightbetween0and250px, with a CSS transition to smooth the change. - Fixed the typo
ddocumentin your original code (that would have broken rendering entirely!).
Solution 2: Using react-spring
If you want more control over animations (like custom easing, spring physics), react-spring is a great choice. Here's how to implement it correctly:
Step-by-Step Fix:
- Add the react-spring CDN to your HTML.
- Use the
useSpringhook to create animated styles based on theisOpenstate. - Wrap your content in an
animated.divto apply the spring animation.
Updated code:
const { useState } = React; const { useSpring, animated } = reactSpring; // Import from react-spring const Example = ({ title }) => { const [isOpen, setIsOpen] = useState(false); // Define spring animation for height const contentStyle = useSpring({ height: isOpen ? "250px" : "0", overflow: isOpen ? "scroll" : "hidden", config: { tension: 200, friction: 20 } // Adjust spring physics here }); return ( <> <div style={{ position: "relative", width: "100%", height: "100%", backgroundColor: "tomato" }}></div> <div className="panel" style={{ position: "absolute", bottom: 20, right: 20, backgroundColor: "pink", width: 200, padding: 15 }}> <div>Title</div> <div onClick={() => setIsOpen(!isOpen)} style={{ cursor: "pointer" }}> {isOpen ? "Close" : "Open"} </div> {/* Use animated.div for spring animation */} <animated.div style={contentStyle}> Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? </animated.div> </div> </> ); }; ReactDOM.render( <Example title="Example using Hooks:" />, document.getElementById("react") );
html, body { width: 100%; height: 100%; } #react { width: 100%; height: 100%; }
<div id="react"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <!-- Add react-spring CDN --> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-spring/8.0.27/react-spring.min.js"></script>
Key Notes:
- We import
useSpringandanimatedfrom react-spring to create the animation. - The
contentStyleobject holds the animated properties—react-spring handles interpolating between the open/closed values automatically. - You can tweak the
configobject to adjust the spring's tension/friction for different animation feels.
内容的提问来源于stack exchange,提问作者marielle




