공식 홈페이지: https://www.framer.com/motion/
리액트용 모션 라이브러리입니다.
이것저것 세련된 애니메이션 효과들을 쉽게 사용할 수 있습니다.
npm install framer-motion
import { motion } from "framer-motion"
HTML, SVG 요소에 motion
을 붙여줍니다.
<motion.div animate={{ scale: 0.5 }} />
styled-component를 사용하는 경우에는 styled(motion.html요소)
로 작성합니다.
const Box = styled(motion.div)`...`;
motion
컴포넌트의 prop을 넣어서 애니메이션을 적용합니다. (prop 값은 맘대로 정해도됨)initial
: 애니메이션이 들어가기 전 초기상태animate
: 애니메이션 효과variants
: initial
과 animate
의 상태를 정리해놓은 오브젝트입니다. https://www.framer.com/docs/transition/ 로 가면 다양한 애니메이션 효과들이 있습니다.
const variants = {
hidden: { opacity: 0 },
visible: { opacity: 1 },
}
return (
<motion.div
initial="hidden"
animate="visible"
variants={variants}
/>
)
임시 이미지를 넣은 데모 버전입니다. 전체 코드는 여기서 봐주세요❤
AnimatePresence
를 이용하여 슬라이드를 만듭니다.import { AnimatePresence, motion } from "framer-motion";
import 해주세요!custom
prop을 이용하여 슬라이드 애니메이션의 방향을 바꿉니다. <Wrapper>
<SlideWrap>
<AnimatePresence custom={back}>
<Box
custom={back}
variants={boxVariants}
src={images[imageIndex]}
initial="entry"
animate="center"
exit="exit"
key={visible}
/>
</AnimatePresence>
</SlideWrap>
<button onClick={prevPlease}>prev</button>
<button onClick={nextPlease}>next</button>
</Wrapper>
image-data.js
파일을 만들어서 이미지 주소들을 정리했습니다.export const images = [
"https://via.placeholder.com/250x250?text=1",
"https://via.placeholder.com/250x250?text=2",
"https://via.placeholder.com/250x250?text=3"
];
motion
과는 달리 종료 애니메이션exit
를 작성해야합니다.custom
prop을 지정하지 않고 작성했습니다.wrap(min:number, max:number, v:number)
import { wrap } from "popmotion";
const [visible, setVisible] = useState(0);
//박스마다 이미지 적용
const imageIndex = wrap(0, images.length, visible);
...
<Box
variants={boxVariants}
src={images[imageIndex]}
initial="entry"
animate="center"
exit="exit"
key={visible}
/>
custom
prop을 지정하지 않고 작성했습니다. const nextPlease = () => {
setVisible((prev) =>
prev === images.length - 1 ? images.length - 1 : prev + 1
);
};
const prevPlease = () => {
setVisible((prev) => (prev === 0 ? 0 : prev - 1));
};
<button onClick={prevPlease}>prev</button>
<button onClick={nextPlease}>next</button>
custom
prop을 지정하지 않고 작성했습니다.const boxVariants = {
//등장 애니메이션 (애니메이션 진행률:0%)
entry:{
x: 500,
opacity: 0,
scale: 0
},
//메인 애니메이션 (50%, 슬라이드가 가운데로 왔을 때의 상태)
center: {
opacity: 1,
x: 0,
scale: 1,
transition: { duration: 0.5 }
},
//종료 애니메이션 (100%)
exit:{
x: -500,
opacity: 0,
scale: 0,
transition: { duration: 0.5 }
}
};
중간체크!
next 버튼을 누를 때 오=>왼으로 잘 넘어가서 보기 좋은데
prev 버튼을 누르면 어딘가 어색해보입니다.
<AnimatePresence>
의 custom
prop을 이용해 prev 버튼을 눌렀을 때의 애니메이션 방향을 바꿔보겠습니다.
useState
를 이용하여 방향의 상태를 정합니다.//방향 상태
const [back, setBack] = useState(false);
//next 버튼
const nextPlease = () => {
//next 때는 false
setBack(false);
setVisible((prev) =>
prev === images.length - 1 ? images.length - 1 : prev + 1
);
};
//prev 버튼
const prevPlease = () => {
//prev 때는 true
setBack(true);
setVisible((prev) => (prev === 0 ? 0 : prev - 1));
};
(back)=>({...})
블록 괄호로 감싸주는 거 잊지 않기!const boxVariants = {
entry: (back: boolean) => ({
//back일 때(prev 버튼을 눌렀을 때) 반대방향으로
x: back ? -500 : 500,
opacity: 0,
scale: 0
}),
center: {
opacity: 1,
x: 0,
scale: 1,
transition: { duration: 0.5 }
},
exit: (back: boolean) => ({
//back일 때(prev 버튼을 눌렀을 때) 반대방향으로
x: back ? 500 : -500,
opacity: 0,
scale: 0,
transition: { duration: 0.5 }
})
};
<AnimatePresence>
와 자식 요소에도 custom
prop을 추가합니다.<AnimatePresence custom={back}>
<Box
custom={back}
variants={boxVariants}
src={images[imageIndex]}
initial="entry"
animate="center"
exit="exit"
key={visible}
/>
</AnimatePresence>
끝입니다!! 참 쉽죠?
다음 포스트는 응용편으로 무한 슬라이드 + 모바일 해상도 한정 스와이퍼에 대해 작성하겠습니다.
코로나때문에 몸상태가 메롱이라서 한꺼번에 못쓰겟네요...ㅠㅠㅠ
응용편에 보여드릴 슬라이드입니다. 넷플릭스 클론인데 강의 내용 외에 몇몇 기능들을 추가했습니다.
framer-motion 공식 홈페이지 - https://www.framer.com/motion/
슬라이드 예제 - https://codesandbox.io/s/pqvx3
wrap - popmotion - https://popmotion.io/popcorn/api/wrap/
React JS 마스터클래스 - 노마드코더 https://nomadcoders.co/react-masterclass
감사합니다! 덕분에 문제였던 부분을 해결했어요!!