[FRAMER MOTION] Variants
학습일 : 2023. 05. 11
Variants 을 사용하게 되면
1. 코드가 깔끔해짐
2. 많은 애니메이션들을 하나로 연결시켜줌
Variant란 비유하자면
내 애니메이션의 stage(무대)이다.
예를 들면, initial이 있을 수도 있고 showing, hidden, from, to, 0%, 100% 등등
내가 원하는 무엇이든 될 수 있다.
이 variant를 자바스크립트 오브젝트에 넣어 작성해주도록 한다.
이름은 자유롭게 지어주고 적용해주면 된다.
const myVars = {
// 초기상태 - start라고 이름 지어 주겠음
// 이전의 코드에서 initial 부분을 이쪽으로 옮겨주겠음.
start : { scale: 0 },
// 최종 상태 - end라고 이름 지어 주겠음
// 이전의 코드에서 animate, transition 부분을 이쪽으로 옮겨주겠음.
end : { scale: 1, rotateZ: 360, }
}
다 옮겨주었으니
이전 코드에서 initial, animate, transition prop들은 지워주도록 한다.
이제 이 myVars라는 이름의 variants prop을 사용하기만 하면 된다.
사용하는 방법은 아래와 같다.
<Box variants={myVars} initial="start" animate="end"/>
또는
<Box variants={myVars} initial={myVars.start} animate={myVars.end}/>
실행결과
저번과 똑같은 결과가 정상적으로 나옴
이제 이런걸 만들어 보고자 하는데,
스타일링을 해주고
<App.tsx>
import { styled } from "styled-components";
import { motion } from "framer-motion";
// style
const Wrapper = styled.div`
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
`;
// 박스
const Box = styled(motion.div)`
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 40px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
display: grid;
grid-template-columns: repeat(2, 1fr);
`;
// 원
const Circle = styled(motion.div)`
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
background-color: white;
height: 70px;
width: 70px;
border-radius: 35px;
place-self: center; // 원들이 박스에서 center로 위치하게 됨
`;
function App() {
return (
<Wrapper>
<Box>
<Circle />
<Circle />
<Circle />
<Circle />
</Box>
</Wrapper>
);
}
export default App;
1. Box가 먼저 나타남
2. 원들이 나타남
이걸 위해 variants를 만들어주도록 하겠음.
const boxVariants = {
start: {},
end: {},
}
그리고 Box 컴포넌트에 prop전달
<Box variants={boxVariants} initial="start" animate="end">
<App.tsx>
박스의 효과를 먼저 만들었다.
import { styled } from "styled-components";
import { motion } from "framer-motion";
// style
const Wrapper = styled.div`
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
`;
// 박스
const Box = styled(motion.div)`
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 40px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
display: grid;
grid-template-columns: repeat(2, 1fr);
`;
// 원
const Circle = styled(motion.div)`
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
background-color: white;
height: 70px;
width: 70px;
border-radius: 35px;
place-self: center; // 원들이 박스에서 center로 위치하게 됨
`;
// Variants
const boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
opacity: 1,
scale: 1,
transition: {
type: "spring",
duration: 2,
bounce: 0.5,
},
},
};
function App() {
return (
<Wrapper>
<Box variants={boxVariants} initial="start" animate="end">
<Circle />
<Circle />
<Circle />
<Circle />
</Box>
</Wrapper>
);
}
export default App;
실행결과
다음은 원 4개의 애니메이션을 만들어볼 것이다.
Circle컴포넌트는
Box의 자식 컴포넌트 이기 때문에
기본값으로 Motion이 initial과 animate를 준다.
따라서
<App.tsx>
circleVariants에도 이름을 start, end로 Box와 똑같이 부여해주었다.
기본적으로 motion은 부모 컴포넌트의 것을 자식들 각각에 복붙해주기 때문이다.
import { styled } from "styled-components";
import { motion } from "framer-motion";
// style
const Wrapper = styled.div`
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
`;
// 박스
const Box = styled(motion.div)`
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 40px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
display: grid;
grid-template-columns: repeat(2, 1fr);
`;
// 원
const Circle = styled(motion.div)`
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
background-color: white;
height: 70px;
width: 70px;
border-radius: 35px;
place-self: center; // 원들이 박스에서 center로 위치하게 됨
`;
// Variants
const boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
opacity: 1,
scale: 1,
transition: {
type: "spring",
duration: 2,
bounce: 0.5,
},
},
};
const circleVariants = {
start: {
scale: 0,
},
end: {
scale: 2,
transition: {
type: "spring",
bounce: 0.8,
},
},
};
function App() {
return (
<Wrapper>
<Box variants={boxVariants} initial="start" animate="end">
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
</Box>
</Wrapper>
);
}
export default App;
따라서 이제 이 Box와 Circle은
둘 다 동일한 initial인 start, animate인 end를 가지게 된다.
start, end란 이름을 같게 해주었기 때문이다.
import { styled } from "styled-components";
import { motion } from "framer-motion";
// style
const Wrapper = styled.div`
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
`;
// 박스
const Box = styled(motion.div)`
width: 200px;
height: 200px;
background-color: rgba(255, 255, 255, 0.2);
border-radius: 40px;
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
display: grid;
grid-template-columns: repeat(2, 1fr);
`;
// 원
const Circle = styled(motion.div)`
box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
background-color: white;
height: 70px;
width: 70px;
border-radius: 35px;
place-self: center; // 원들이 박스에서 center로 위치하게 됨
`;
// Variants
const boxVariants = {
start: {
opacity: 0,
scale: 0.5,
},
end: {
opacity: 1,
scale: 1,
transition: {
type: "spring",
duration: 2, // box가 마무리 될때까지 2초 걸림
bounce: 0.5,
// delayChildren: 0.5, // 모든 자식 통째로 0.5초의 delay주기
staggerChildren: 0.2, // 자식1, 자식2, 자식3, 자식4가 차례로 0.2초 간격으로 나옴
},
},
};
const circleVariants = {
start: {
opacity: 0,
y: 10,
},
end: {
opacity: 1,
y: 0, // 밑에서부터 위로 올라옴
},
};
function App() {
return (
<Wrapper>
<Box variants={boxVariants} initial="start" animate="end">
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
<Circle variants={circleVariants} />
</Box>
</Wrapper>
);
}
export default App;
실행결과