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 {
|
.interview-status-animation-wrapper {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
padding: 10px 0;
|
|
||||||
background: linear-gradient(135deg, #f7faff 0%, #ffffff 100%);
|
background: linear-gradient(135deg, #f7faff 0%, #ffffff 100%);
|
||||||
border-top: 1px solid #e5e6eb;
|
border-top: 1px solid #e5e6eb;
|
||||||
animation: slideDown 0.3s ease-out;
|
|
||||||
overflow: hidden;
|
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 {
|
from {
|
||||||
max-height: 0;
|
max-height: 0;
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
|
padding: 0;
|
||||||
}
|
}
|
||||||
to {
|
to {
|
||||||
max-height: 200px;
|
max-height: 200px;
|
||||||
opacity: 1;
|
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;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
transform: scale(0.9);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.interview-status-animation-wrapper.expanding .animation-container {
|
||||||
|
transform: scale(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.animation-container svg {
|
.animation-container svg {
|
||||||
|
|||||||
@@ -21,6 +21,22 @@ export default ({ statusText, isOpen }) => {
|
|||||||
const animationContainer = useRef(null);
|
const animationContainer = useRef(null);
|
||||||
const lottieInstance = useRef(null);
|
const lottieInstance = useRef(null);
|
||||||
const [animationData, setAnimationData] = useState(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(() => {
|
useEffect(() => {
|
||||||
if (isOpen && statusText) {
|
if (isOpen && statusText) {
|
||||||
@@ -35,7 +51,7 @@ export default ({ statusText, isOpen }) => {
|
|||||||
}, [isOpen, statusText]);
|
}, [isOpen, statusText]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (animationData && animationContainer.current && isOpen) {
|
if (animationData && animationContainer.current && isVisible) {
|
||||||
// 清除之前的动画实例
|
// 清除之前的动画实例
|
||||||
if (lottieInstance.current) {
|
if (lottieInstance.current) {
|
||||||
lottieInstance.current.destroy();
|
lottieInstance.current.destroy();
|
||||||
@@ -56,12 +72,12 @@ export default ({ statusText, isOpen }) => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}, [animationData, isOpen]);
|
}, [animationData, isVisible]);
|
||||||
|
|
||||||
if (!isOpen) return null;
|
if (!isVisible) return null;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="interview-status-animation-wrapper">
|
<div className={`interview-status-animation-wrapper ${animationClass}`}>
|
||||||
<div className="animation-container" ref={animationContainer} />
|
<div className="animation-container" ref={animationContainer} />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user