공식문서를 참고했지만 내 눈에 쉽게 변형했다. 가장 먼저 공식문서를 보는 습관을 길러야겠다.
AnimateSharedLayout
여러 구성 요소 간에 레이아웃 변경을 애니메이션화합니다.
이 전에는 링크를 클릭했을 때 변경하는 요소만 알고 있었는데 레이아웃 변경 시도 가능했다.
import styled, { keyframes } from "styled-components";
import { motion, AnimateSharedLayout, AnimatePresence } from "framer-motion";
const items = [
{
id: "1",
title: "",
subtitle: "",
img:"",
},
{
id: "2",
title: "",
subtitle: "",
img:"",
},
{
id: "3",
title: "",
subtitle: "",
img:"",
}
]
const Accordion = () => {
return (
<AnimateSharedLayout>
<Container>
<motion.ul layout transition={{ duration: 0.3, ease: [0.43, 0.13, 0.23, 0.96] }}>
{items.map(item => (
<Item key={item} item={item} />
))}
</motion.ul>
<h4>
iepppop.velog
</h4>
</Container>
</AnimateSharedLayout>
)
}
export default Accordion;
const Container = styled(motion.div)`
margin:200px auto 0 auto;
width:50%;
text-align:center;
ul{
width: 300px;
background:#fff;
margin:0 auto;
}
`
<motion.div layout />
motion.div
와layout
은 레이아웃 변경 사항을 자동으로 애니메이션화 한다.
솔직히 이렇게 읽어도 뭔 소린지 몰랐다.그러나 역시 몇 시간 동안 해보니까 감이 왔다 ㅎ 말 그대로 자동으로 애니메이션 효과를 넣어준다는 것.
그래서 전체 ul부분과 Item.js 타이틀과 내용에 넣었다.
Item.js
import { motion, AnimatePresence, layout } from 'framer-motion';
import { useState } from 'react';
import styled from 'styled-components';
const Item = ({ item }) => {
const [isOpen, setIsOpen] = useState(false);
const toggleOpen = () => setIsOpen(!isOpen);
return (
<>
<ItemWrap onClick={toggleOpen} layout transition={{ duration: 0.3, ease: [0.43, 0.13, 0.23, 0.96] }} key={item}>
<motion.h1>{item.title}</motion.h1>
<Img><img src={item.img} alt={item.title} /></Img>
</ItemWrap>
<AnimatePresence>
{isOpen && (
<SubWrap>
<motion.h5 layout
initial={{ y: -10, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
exit={{ opacity: 0 }}
transition={{ duration: 0.3, ease: [0.43, 0.13, 0.23, 0.96] }}
>{item.subtitle}</motion.h5>
</SubWrap>
)}
</AnimatePresence>
</>
)
}
export default Item;
const ItemWrap = styled(motion.li)`
cursor: pointer;
display:flex;
align-items:center;
justify-content:space-between;
border-top:1px solid #eee;
border-bottom:1px solid #eee;
margin-top:-1px;
background: white;
overflow: hidden;
h1{
padding:22px 30px 21px 30px;
font-size:15px;
z-index:1;
opacity:0.9;
}
`
const Img = styled(motion.div)`
width:40px;
height:40px;
overflow: hidden;
border-radius:50%;
margin:0 30px 0 0;
display:flex;
justify-content:center;
align-items:center;
img{
width:32px;
height:32px;
border-radius:50%;
vertical-align:bottom;
}
`
const SubWrap = styled(motion.div)`
font-size:15px;
height:auto;
width:100%;
display:flex;
flex-direction: column;
background: white;
h5{
padding:20px 30px;
font-weight:500;
line-height:150%;
text-align:left;
}
:last-child{
border-radius:0 0 20px 20px;
}
`
효과가 들어가야 할 제목 부분과 하단 설명 부분에도 layout을 넣어줬다.
이건 초반에 만든 건데 보면 확실히 뚝뚝 끊기는 걸 볼 수 있다.
잔 버벅거림으로 인해 이거만 5시간 잡고 있었던 듯 하다. styled-components에 (motion.div)를 제대로 안넣고 layout만 넣고 있으니 바뀌지를 않았을 뿐.... ㅠ 바보아냐?