为了进一步了解 React,我使用
react-router-dom
、styled-components
和 framer-motion
创建了一个项目。
我的版本是这样的。
package-json:
....
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-icons": "^4.7.1",
"react-router-dom": "^6.8.1",
"react-scripts": "5.0.1",
"styled-components": "^5.3.6",
....
我的模态有一个不透明的简单动画,并且容器应用了
backdrop-filter: blur(10px)
。我希望模态开始淡入时立即应用模糊效果。现在,动画已经执行,并且只有在应用背景滤镜之后才执行。我觉得这很奇怪,因为所有其他样式,例如 background-color
,都是从动画开始的那一刻起应用的。
我的组件
Modal.js
:
import { IntroModal, ModalContainer } from './Modal.styled';
import { useEffect, useRef } from 'react';
import { motion } from 'framer-motion';
import { AnimatePresence } from 'framer-motion';
import { IoMdClose } from 'react-icons/io';
const Modal = ({ isOpen, toggleModal, closeOnOutsideClick, children }) => {
const modalRef = useRef(null);
useEffect(() => {
const handleClickOutside = (event) => {
if (
closeOnOutsideClick &&
modalRef.current &&
!modalRef.current.contains(event.target)
) {
toggleModal();
}
};
document.addEventListener('mousedown', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
};
}, [modalRef, closeOnOutsideClick, toggleModal]);
const closeButtonStyle = {
color: 'white',
fontSize: '1.5rem',
cursor: 'pointer',
filter: 'drop-shadow(0px 0px 2px #000)',
};
!isOpen
? (document.body.style.overflow = 'hidden')
: (document.body.style.overflow = 'auto');
return (
<AnimatePresence>
!isOpen && (
<motion.div
style={isOpen ? { display: 'none' } : null}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
key={isOpen}
>
<IntroModal>
<ModalContainer ref={modalRef}>
<button onClick={toggleModal}>
<IoMdClose style={closeButtonStyle} />
</button>
{children}
</ModalContainer>
</IntroModal>
</motion.div>
)
</AnimatePresence>
);
};
export default Modal;
Modal.styled.js
:
import styled from 'styled-components';
export const IntroModal = styled.div`
position: fixed;
display: flex;
justify-content: center;
align-items: center;
z-index: 11;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.7);
button {
position: absolute;
top: 0.3rem;
right: 0.3rem;
padding: 0.5rem;
border: none;
background: transparent;
transition: transform 0.2s ease-in-out;
&:hover {
transform: scale(1.1);
}
}
img {
width: 50%;
box-shadow: 0 0 15px #000;
margin-top: 1rem;
}
p {
font-weight: bold;
font-size: 1rem;
padding: 0 1rem;
}
`;
export const ModalContainer = styled.div`
backdrop-filter: blur(10px);
position: absolute;
top: 50%;
width: 30%;
background-color: rgba(38, 50, 50, 0.5);
text-align: center;
transform: translateY(-50%);
padding: 1rem 0.2rem 0.5rem;
border-top: 0.7px solid #b6b6b666;
border-right: 0.7px solid #8e8e8e66;
border-bottom: 0.7px solid #000;
border-left: 0.7px solid #77777766;
border-radius: 18px;
box-shadow: 0 0 1rem 0 #000;
min-height: 200px;
display: inherit;
flex-wrap: wrap;
flex-direction: row;
justify-content: center;
align-items: center;
@media screen and (max-width: 768px) {
width: 80vw;
height: 80vh;
}
`;
export const ModalWrapper = styled.div`
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 50%;
height: 25%;
font-size: 2rem;
`;
这是它现在外观的 gif:
我尝试将样式直接应用于组件,例如
style={backdropFilter: blur(10px)
,并将其包含在动画中,如下所示(分别在外部motion.div
和ModalContainer
中尝试过):
<motion.div
style={isOpen ? { display: 'none' } : null}
initial={{ opacity: 0, backdropFilter: 'blur(0px)' }}
animate={{ opacity: 1, backdropFilter: 'blur(10px)' }}
exit={{ opacity: 0, backdropFilter: 'blur(0px)' }}
key={isOpen}
>
<IntroModal>
<motion.ModalContainer ref={modalRef}
initial={{ opacity: 0, backdropFilter: 'blur(0px)' }}
animate={{ opacity: 1, backdropFilter: 'blur(10px)' }}
exit={{ opacity: 0, backdropFilter: 'blur(0px)' }}
key={isOpen}
>
<button onClick={toggleModal}>
<IoMdClose style={closeButtonStyle} />
</button>
{children}
</motion.ModalContainer>
</IntroModal>
</motion.div>
非常感谢任何提示和建议!
我不相信你可以制作动画
backdrop-filter: blur
,所以你只看到它的两种状态 - blur(0)
和blur(10px)
,而不是所有中间动画步骤,所以看起来它是在其他转换之后应用的完成。
这个答案建议从
backdrop-filter: blur(10px) opacity(0);
到 backdrop-filter: blur(4px) opacity(1);
进行动画处理,因为 backdrop-filter: opacity
可以进行动画处理。
我有完全相同的问题;当任何与变换相关的动画触发时,模糊效果就会消失。不确定问题是来自 CSS 还是 Framer-Motion。 但如果问题归咎于 Framer-Motion,我想你可以使用 React-Transition-Group 来实现这个动画,也许问题就可以解决。一旦找到解决方案,我会写另一个答案。 🤷