프론트엔드/CSS
[CSS] Framer motion을 이용한 슬롯 머신 구현
순코딩
2023. 11. 20. 16:29
기능
배열에 있는 모든 요소를 순회하며 슬롯 머신 처럼 애니메이팅 한다.
시연 영상
사용 방법
1. styled-components 설치
npm install styled-components
2. framer-motion 설치
npm install framer-motion
3. SlotMachine.jsx 파일 생성 후 아래 코드 복붙
import React, { useRef, useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
import styled from "styled-components";
const SlotMachine = () => {
// useRef를 사용하여 motion.div의 DOM 요소에 접근하는 참조 생성
const slotItemRef = useRef(null);
// 슬롯에 표시될 문자열을 담은 배열
const arr = ['사과','포도','딸기','배','복숭아','수박','멜론','망고'];
// 현재 보여지고 있는 슬롯의 인덱스를 나타내는 상태 변수
const [currentIndex, setCurrentIndex] = useState(0);
// 애니메이션이 완료되면 호출되는 함수
const onAnimationComplete = () => {
// 다음 슬롯으로 이동하기 위해 currentIndex 업데이트
setCurrentIndex((prev) => (prev + 1) % arr.length);
};
// Framer motion 애니메이션에 필요한 속성값 객체
const [slotVariants, setSlotVariants] = useState({
initial: { opacity: 1, y: 40 }, // 텍스트는 밑에서 시작해서
animate: { opacity: 0.7, y: -40 }, // 위로 올라온다
transition: { duration: 0.15, times: [0, 1] }, // initial 상태에서 animate 상태까지 도달하는 데에 걸리는 시간은 duration
});
// 슬롯 멈추기 함수
const slotStop = () => {
changeSlotSpeed(0, 0.5); // 속도 줄이기 1
changeSlotSpeed(2000, 1); // 속도 줄이기 2
changeSlotSpeed(4000, 2); // 속도 줄이기 3
setTimeout(() => {
setSlotVariants(() => ({})); // 슬롯 멈추기(애니메이션 속성 객체를 모두 초기화 시켜 슬롯을 멈춘다.)
}, 8200);
};
// 슬롯 속도 변화 함수
const changeSlotSpeed = (delay, speed) => {
setTimeout(() => {
setSlotVariants((prev) => ({
...prev,
transition: { duration: speed, times: [0, 1] },
}));
}, delay);
};
return (
<>
<Container>
{/* 슬롯 컨테이너 */}
<SlotContainer>
{/* 애니메이션의 등장,퇴장 감지 / onAnimationComplete을 사용하려면 필요함 */}
<AnimatePresence>
{/* 애니메이션 박스 */}
<motion.div
key={currentIndex} // 현재 슬롯의 인덱스를 키로 사용하여 애니메이션 처리
ref={slotItemRef}
variants={slotVariants}
initial={slotVariants.initial}
animate={slotVariants.animate}
transition={slotVariants.transition}
// 애니메이션이 완료될 때 호출되는 함수 지정
onAnimationComplete={onAnimationComplete}
>
{/* 슬롯 아이템 보이는 곳 */}
<SlotItemBox>{arr[currentIndex]}</SlotItemBox>
</motion.div>
</AnimatePresence>
</SlotContainer>
{/* 멈추기 버튼, 클릭 이벤트 핸들러 추가 필요 */}
<StopButton onClick={slotStop}>멈춰</StopButton>
</Container>
</>
);
};
const Container = styled.div`
width: 420px;
height: 820px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
`;
// 슬롯을 감싸는 스타일이 적용된 컨테이너 스타일링
const SlotContainer = styled.div`
width: 200px;
height: 50px;
display: flex;
justify-content: center;
align-items: center;
overflow: hidden;
border: 1px solid black;
background-color: black;
`;
const SlotItemBox = styled.div`
color: white;
font-size: 20px;
font-weight: bold;
`;
const StopButton = styled.button`
background-color: #bcd2a1;
color: white;
font-size: 15px;
font-weight: bold;
width: 200px;
&:hover {
background-color: #bcd2a1;
opacity: 0.9;
}
`;
export default SlotMachine;