-
메인 화면 Carousel 구현하기project/main 2023. 3. 22. 22:52
첫 생각
처음에는 키프레임을 사용하고 애니메이션 시간을 정해서 움직이게 하면 되겠다! 라는 생각을 가지고 구현을 했다.
// MainLayout.tsx const ContentBox = styled.div<MainLayoutProps>` width: 400%; display: flex; margin-left: ${(props) => (props.img ? `300%` : `none`)}; animation-duration: ${(props) => (props.img ? `18s` : `none`)}; animation-name: ${(props) => (props.img ? `img` : `none`)}; animation-iteration-count: ${(props) => (props.img ? `infinite` : `none`)}; @keyframes img { 18.75% { margin-left: 300%; } 25% { margin-left: 100%; } 43.75% { margin-left: 100%; } 50% { margin-left: -100%; } 68.75% { margin-left: -100%; } 75% { margin-left: -300%; } 93.75% { margin-left: -300%; } 100% { margin-left: 300%; } } `; // MainDontMove.tsx const MainDontMove = () => { const handleLeft = () => { // 애니메이션을 멈추고 이동 일정 시간 후 다시 애니메이션 작동 }; const handleRight = () => { // 애니메이션을 멈추고 이동 일정 시간 후 다시 애니메이션 작동 }; return ( <MainDontMoveContauner> <MainArrowButton arrow={<SlArrowLeft />} onClick={handleLeft} /> <MainArrowButton arrow={<SlArrowRight />} onClick={handleRight} /> </MainDontMoveContauner> ); }; export default MainDontMove;
- 환경은 React, Typescript, styled-component이다.
- MainLayout.tsx 컴포넌트에서 contentBox 태그의 애니메이션 반복횟수, 사용 할 키프레임 이름, 한바퀴에 사용되는 시간을 설정했다.
- 키프레임은 margin-left의 위치를 바꿔가며 움직이게 설정했다.
- MainDontMove.tsx 컴포넌트에서 arrowButton을 클릭하면 클릭한 방향으로 이동하게 끔 만들려고 했다.
- useRef를 사용해 애니메이션이 동작하는 태그의 주소를 불러와서 CSS를 추가하여 애니매이션을 멈추고 arrow버튼의 방향으로 이동하게 한 후 setTimeout함수를 사용하여 일정 시간이 지나면 다시 애니메이션을 시작하도록 구상을 했다.
에러
이미지를 멈추는데까지는 성공했다. 하지만 그 후에 이미지가 이동하지 않았다.
원인
- css를 추가해서 margin-left를 변경하려 했지만 변하지 않았다. 개발자 도구로 확인했을때 태그 style속성에 추가되는건 확인되었지만 console.log를 찍어보면 margin이 바뀌지 않았다.
- 초기값을 태그 속성에 style을 주어 해봤지만 위와 마찬가지였다.
- 애니메이션을 다시 실행시킬때 진행도를 이동한곳의 진행도로 바꾸고 다시 시행시키기가 내 지식으로는 힘들었고 검색을 해봤지만 애니메이션을 교체하는 방법은 있어도 원하는 진행도로 이동하고 거기서 다시 재시작하는 내용은 찾을수 없었다.
해결
결국 내가 생각한 방식인 애니메이션을 먼저 만들고 버튼을 구현하는 방법이 잘못됐다는 결론에 도달했다. 그래서 먼저 버튼을 구현하고 애니메이션을 어떻게 구현할지 생각을 해보기로 했다.
// MainLayout.tsx const ContentBox = styled.div<{ img?: boolean; page: number }>` width: ${(props) => (props.img ? `400%` : `100%`)}; display: flex; margin-left: ${(props) => (props.img ? `300%` : `none`)}; transition: ${(props) => (props.img ? `1s` : `none`)}; transform: ${(props) => props.img ? `translateX(-${props.page * 25}%)` : `none`}; `; const [page, setPage] = useState(0); const handlePreClick = () => { setPage((prev) => (prev - 1 + 4) % 4); }; const handleNextClick = () => { setPage((prev) => (prev + 1) % 4); }; ... return( ... <MainDontMove handlePreClick={handlePreClick} handleNextClick={handleNextClick} /> ... ) // MainDontMove.tsx const MainDontMove = ({ handlePreClick, handleNextClick, }: MainDontMoveProps) => { const handleLeft = () => { handlePreClick(); }; const handleRight = () => { handleNextClick(); }; return ( <MainDontMoveContauner> <MainArrowButton arrow={<SlArrowLeft />} onClick={handleLeft} /> <MainArrowButton arrow={<SlArrowRight />} onClick={handleRight} /> </MainDontMoveContauner> ); };
- MainLayout.tsx의 ContentBox 태그 속성 중 translateX의 값이 page의 상태에 따라 동적을 변함
- MainLayout.tsx에서 이벤트가 발생할 때마다 이미지의 page가 바뀌는 함수 작성
- MainLayout.tsx의 자식 컴포넌트인 MainDontMove.tsx 컴포넌트에 이미지의 page가 바뀌는 함수 전달
- MainDontMove.tsx 컴포넌트에서 arrowButton 클릭 이벤트에 전달받은 이미지의 page가 바뀌는 함수 적용
// MainLayout.tsx useEffect(() => { const interval = setInterval(() => { setPage((prev) => (prev + 1) % 4); }, 4000); return () => clearInterval(interval); }, [page, img]);
- useEffect에 setInterval함수를 사용하여 4초 후에 페이지가 변하게 구현
'project > main' 카테고리의 다른 글
axios 요청을 redux안에 넣었을 때 발생하는 에러 (0) 2023.03.24 React환경에서 S3에 배포 후 새로고침 에러 (0) 2023.03.23 무한 스크롤 중복 데이터 에러 수정 (0) 2023.03.21 개발용 토큰 환경변수 지정, axios defalt 설정 (0) 2023.03.20 github action 환경 변수 설정 (0) 2023.03.19