React中集合容器展开动画实现方法咨询
实现集合数量变化时容器高度的平滑过渡动画
纯CSS方案(快速实现)
这种方案无需额外JS逻辑,利用CSS transition 和 max-height 属性实现过渡:
- 给集合容器设置默认的
max-height(对应显示少量项目时的高度),并添加过渡效果 - 点击"Show more"时,给容器添加类名,将
max-height设为足够容纳所有项目的数值(需根据实际内容调整)
示例代码:
.collection-container { max-height: 200px; /* 显示少量项目的高度 */ overflow: hidden; transition: max-height 0.3s ease; } .collection-container.expanded { max-height: 1000px; /* 足够容纳所有项目的高度 */ }
// React组件中切换类名 function Collection() { const [showMore, setShowMore] = useState(false); const items = Array.from({ length: showMore ? 10 : 3 }, (_, i) => `Item ${i+1}`); return ( <div> <div className={`collection-container ${showMore ? 'expanded' : ''}`}> {items.map((item, idx) => ( <div key={idx} style={{ padding: '10px', borderBottom: '1px solid #eee' }}> {item} </div> ))} </div> <button onClick={() => setShowMore(!showMore)}> {showMore ? 'Show less' : 'Show more'} </button> </div> ); }
React动态高度方案(精准过渡)
如果内容高度不确定,纯CSS的max-height可能导致过渡时长不准确,此时可以通过React的ref获取容器实际高度,动态触发过渡:
import { useState, useRef, useEffect } from 'react'; function Collection() { const [showMore, setShowMore] = useState(false); const containerRef = useRef(null); const [containerHeight, setContainerHeight] = useState('auto'); const items = Array.from({ length: showMore ? 10 : 3 }, (_, i) => `Item ${i+1}`); useEffect(() => { if (!containerRef.current) return; // 先固定当前高度,再触发过渡到展开后的实际高度 const currentHeight = containerRef.current.offsetHeight; setContainerHeight(`${currentHeight}px`); setTimeout(() => { const targetHeight = containerRef.current.scrollHeight; setContainerHeight(`${targetHeight}px`); }, 0); }, [showMore]); // 过渡完成后重置为auto,避免内容变化时高度受限 useEffect(() => { if (!showMore || containerHeight === 'auto') return; const timer = setTimeout(() => setContainerHeight('auto'), 300); // 与transition时长一致 return () => clearTimeout(timer); }, [showMore, containerHeight]); return ( <div> <div ref={containerRef} style={{ height: containerHeight, overflow: 'hidden', transition: 'height 0.3s ease', }} > {items.map((item, idx) => ( <div key={idx} style={{ padding: '10px', borderBottom: '1px solid #eee' }}> {item} </div> ))} </div> <button onClick={() => setShowMore(!showMore)}> {showMore ? 'Show less' : 'Show more'} </button> </div> ); } export default Collection;
动画库方案(简洁高效)
使用framer-motion这类动画库可以快速实现平滑过渡,无需手动处理高度计算:
import { useState } from 'react'; import { motion } from 'framer-motion'; function Collection() { const [showMore, setShowMore] = useState(false); const items = Array.from({ length: showMore ? 10 : 3 }, (_, i) => `Item ${i+1}`); return ( <div> <motion.div style={{ overflow: 'hidden' }} animate={{ height: 'auto' }} transition={{ duration: 0.3 }} > {items.map((item, idx) => ( <div key={idx} style={{ padding: '10px', borderBottom: '1px solid #eee' }}> {item} </div> ))} </motion.div> <button onClick={() => setShowMore(!showMore)}> {showMore ? 'Show less' : 'Show more'} </button> </div> ); } export default Collection;
方案对比
- 纯CSS:适合内容高度固定或可预估的简单场景,代码量最少
- React动态高度:适合内容高度不确定的场景,过渡效果精准
- 动画库:适合快速开发,无需关注底层高度计算,兼容性好
内容的提问来源于stack exchange,提问作者Vadim
相关产品推荐
相关产品推荐

