feat: 优化面试状态动画的展开和收起效果
- 添加expanding和collapsing动画类 - 使用cubic-bezier缓动函数让动画更平滑 - 收起时等待动画完成后再隐藏组件 - 动画容器添加缩放效果增强视觉体验 - 分离展开和收起动画的时间和效果 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,20 +1,42 @@
|
||||
.interview-status-animation-wrapper {
|
||||
width: 100%;
|
||||
padding: 10px 0;
|
||||
background: linear-gradient(135deg, #f7faff 0%, #ffffff 100%);
|
||||
border-top: 1px solid #e5e6eb;
|
||||
animation: slideDown 0.3s ease-out;
|
||||
overflow: hidden;
|
||||
transition: all 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
@keyframes slideDown {
|
||||
.interview-status-animation-wrapper.expanding {
|
||||
animation: expandDown 0.4s ease-out forwards;
|
||||
}
|
||||
|
||||
.interview-status-animation-wrapper.collapsing {
|
||||
animation: collapseUp 0.3s ease-in forwards;
|
||||
}
|
||||
|
||||
@keyframes expandDown {
|
||||
from {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
padding: 0;
|
||||
}
|
||||
to {
|
||||
max-height: 200px;
|
||||
opacity: 1;
|
||||
padding: 10px 0;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes collapseUp {
|
||||
from {
|
||||
max-height: 200px;
|
||||
opacity: 1;
|
||||
padding: 10px 0;
|
||||
}
|
||||
to {
|
||||
max-height: 0;
|
||||
opacity: 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +47,12 @@
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
overflow: hidden;
|
||||
transform: scale(0.9);
|
||||
transition: transform 0.3s ease;
|
||||
}
|
||||
|
||||
.interview-status-animation-wrapper.expanding .animation-container {
|
||||
transform: scale(1);
|
||||
}
|
||||
|
||||
.animation-container svg {
|
||||
|
||||
@@ -21,6 +21,22 @@ export default ({ statusText, isOpen }) => {
|
||||
const animationContainer = useRef(null);
|
||||
const lottieInstance = useRef(null);
|
||||
const [animationData, setAnimationData] = useState(null);
|
||||
const [isVisible, setIsVisible] = useState(false);
|
||||
const [animationClass, setAnimationClass] = useState('');
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setIsVisible(true);
|
||||
setAnimationClass('expanding');
|
||||
} else if (isVisible) {
|
||||
setAnimationClass('collapsing');
|
||||
const timer = setTimeout(() => {
|
||||
setIsVisible(false);
|
||||
setAnimationClass('');
|
||||
}, 300); // 等待收起动画完成
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [isOpen, isVisible]);
|
||||
|
||||
useEffect(() => {
|
||||
if (isOpen && statusText) {
|
||||
@@ -35,7 +51,7 @@ export default ({ statusText, isOpen }) => {
|
||||
}, [isOpen, statusText]);
|
||||
|
||||
useEffect(() => {
|
||||
if (animationData && animationContainer.current && isOpen) {
|
||||
if (animationData && animationContainer.current && isVisible) {
|
||||
// 清除之前的动画实例
|
||||
if (lottieInstance.current) {
|
||||
lottieInstance.current.destroy();
|
||||
@@ -56,12 +72,12 @@ export default ({ statusText, isOpen }) => {
|
||||
}
|
||||
};
|
||||
}
|
||||
}, [animationData, isOpen]);
|
||||
}, [animationData, isVisible]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
if (!isVisible) return null;
|
||||
|
||||
return (
|
||||
<div className="interview-status-animation-wrapper">
|
||||
<div className={`interview-status-animation-wrapper ${animationClass}`}>
|
||||
<div className="animation-container" ref={animationContainer} />
|
||||
</div>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user