넷째주 #19 React Js - framer-motion

김선은·2023년 6월 7일

framer-motion은 리액트에서 애니메이션과 제스처를 쉽게 다룰 수 있게 해주는 라이브러리이다. initail, animate, exit prop에 값을 세팅하면 CSS transitions을 자동 생성하는 방법으로 애니메이션을 만들어준다.

메모 + 참고한 블로그

설치

npm install framer-motion

import { motion } from 'framer-motion'

import { motion, useMotionValue, useMotionValueEvent, useTransform, 
        useScroll } from 'framer-motion'
//import해서 사용할 수 있는 기술이 여러개임

사용

motion을 이용해서 HTML element 불러와야 한다.

  • 모션 컴포넌트로 생성해서 prop에 값 주기

<motion.div
animate={{
         x: 0,
         backgroundColor: "#000",
         boxShadow: "10px 10px 0 rgba(0, 0, 0, 0.2)",
         transitionEnd: {
         display: "none",
        },
}}
/>

<motion.div animate={{ scale: 2 }} />
  • 모션 스타일 컴포넌트 만들기
const Box = styled(motion.div)`
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 10%;
`;

return (
	<Box animate={{ borderRadius: "100px" }}/>
)
  • 모션 스타일 컴포넌트 + variants
const boxVariants = {
  start: {
    opacity: 0,
    scale: 0.5,
  },
  end: {
    scale: 1,
    opacity: 1,
    transition: {
      type: "spring",
      duration: 0.5,
    },
  },
};

return (
<Box variants={boxVariants} initial="start" animate="end">
)
// 주려는 prop 이름을 적고 variants 내의 prop을 입력
// initial과 animate 말고도 whilehover 등이 있음..

Variants

Variants은 컴포넌트가 가질 수 있는 미리 정의된 시각적 state.
variants 객체를 만들어서 원하는 이름의 속성을 만들고 애니메이션 효과를 작성한다.
컴포넌트에 variants prop을 주고 앞서 만든 variants 전달,
원하는 애니메이션 prop 에 variants 객체 안의 프로퍼티 전달. (start, end)
ex) initial, animate, exit, whileHover ...

const boxVariants = {
  start: {
    opacity: 0,
    scale: 0.5,
  },
  end: {
    scale: 1,
    opacity: 1,
  },
};

return (
<Box variants={boxVariants} initial="start" animate="end" />
)

motion의 prop

initail : 애니메이션 시작 명시, 초기 상태
animate : 애니메이션 최종 상태
exit : 애니메이션 종료

whileHover : 마우스 호버
whileTap : 마우스 누르는 동안
drag : 드래그가 가능하게 만듬

prop은 값을 객체로 받고 값이 지정되면 첫 렌더링시에, 또는 변경되면 변경된 값으로 motion 컴포넌트를 애니메이팅 한다.

prop 값으로 쓰는 친구들

scale : 크기 변화
rotate : x, y, z 회전
transition : 부드러운 변화 (색상, 크기, 위치)

  • type: 기본적으로 "spring". "tween" 으로 하면 선형적으로 바뀜 (linear)
  • duration: 진행 속도 & delay: 지연 속도
  • stiffness: 뻣뻣하게 만들어줌
  • damping: 반동을 만들어줌. 0으로 하면 영원히 움직임.
  • mass: 기본값 1. 질량. 무게감을 보여줌. 5로 하면 움직임이 무거워보임
  • bounce: 0~1 사이의 값. 튕기는 정도. stiffness, damping, mass가 있다면 bounce와 duration 은 덮어씌워진다.

Keyframes

<motion.div
  animate={{
    scale: [1, 2, 2, 1, 1],
    rotate: [0, 0, 270, 270, 0],
    borderRadius: ["20%", "20%", "50%", "50%", "20%"],
  }}
/>

값을 array로 넣게 되면 순서대로 실행된다. 기본적으로는 동일한 시간으로 실행되나 transition 프로퍼티를 조정해서 시간값을 수정할 수 있다.


children animation

모션 컴포넌트 부모와 자식의 경우,
부모 모션 컴포넌트에 적용된 initail, animate 속성값은 자식들에게 자동적으로 동일하게 부여된다.

return (
<Box variants={boxVariants} initial="start" animate="end">
  <Circle initial="start" animate="end" />
  <Circle /> // 자동적으로 위 Circle처럼 되어있다.
</Box>
)

Orchestration :
자식요소에 애니메이션 효과 주기. (transition 옵션)
delayChildren : 모든 자식들에게 딜레이 시간(초) 후에 하위 애니메이션이 시작.
staggerChildren : 하위 컴포넌트의 애니메이션에 시차를 둘 수 있음.
예를 들어, staggerChildren이 0.01이면 첫 번째 자식은 0초, 두 번째 자식은 0.01초, 세 번째 자식은 0.02초 지연되는 식. 계산된 stagger 딜레이가 delayChildren에 추가.

inherit: boolean : 부모로부터 variants 변경 사항을 상속하지 않도록 하려면 false로 설정.

const Box = styled(motion.div)`
  display: grid;
  grid-template-columns: 1fr 1fr;
  width: 200px;
  height: 200px;
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 20%;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;

const Circle = styled(motion.div)`
  place-self: center;  //justify-self와 align-self를 합친 축약
  background-color: white;
  width: 70px;
  height: 70px;
  border-radius: 50%;
  box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
`;

const boxVariants = {
  start: {
    opacity: 0,
    scale: 0.5,
  },
  end: {
    scale: 1,
    opacity: 1,
    transition: {
      type: "spring",
      duration: 0.5,
      bounce: 0.5,
      delayChildren: 1, // 자식 요소 모두 1초 딜레이
      staggerChildren: 0.3, //자식 요소에 순차적으로 0.3초 딜레이
    },
  },
};

const circleVariants = {
  start: { opacity: 0, y: 20 },
  end: { opacity: 1, y: 0, transition: { duration: 1 } }, 
  // x와 y는 css가 아닌 motion 좌표 수정 기능. 
  // y에 값을 줘서 살짝 올라오며 생성되도록 보이게 함.
};

function Animation() {
  return (

 <Box variants={boxVariants} initial="start" animate="end">
    <Circle variants={circleVariants} />
    <Circle variants={circleVariants} />
    <Circle variants={circleVariants} />
    <Circle variants={circleVariants} />
   	// boxVarinats와 프로퍼티 이름을 동일하게 만들어서 initial="start"~ 생략 가능
 </Box>
}

hover 와 drag

whileTap: 마우스로 누르는 동안.
drag: 드래그 가능하게 됨. 추가로 x, y값을 줘서 드래그 방향을 결정할 수 있음
whileDrag: 드래그 하는 동안. 추가로 backgroundColor를 rgba값 준다면 색상 변화도 애니메이트
dragElastic: 기본값 0.5 이다. 1로 하면 마우스 커서와 드래그하는 것과 똑같이 움직임
dragSnapToOrigin: 드래그가 끝나면 제자리로.
dragConstraints: 드래그가 되는 공간을 제한.
ex) dragConstraints={{top: -100}} 또는 useRef로 바깥 박스를 잡아서 값으로 주기

const biggerBoxRef = useRef<HTMLDivElement>(null); : ts 사용시
const biggerBoxRef = useRef(null);
return <Box dragConstraints={biggerBoxRef} />

const BiggerBox = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
  flex-wrap: wrap;
  width: 800px;
  height: 800px;
  background-color: rgba(255, 255, 255, 0.2);
  border-radius: 20%;
`;

const boxVariants = {
  hover: { scale: 1.5, rotateZ: 90 }, 
  //Box 컴포넌트에 prop을 whileHover로
  click: { scale: 1, borderRadius: "100px" }, 
  //Box 컴포넌트에 prop을 whileTap으로
};
//variansts 내의 이름은 아무렇게 지어도 상관없지만 
//motion prop과 이름을 같게 만들면 축약으로 사용할 수 있음.

export default function Animation() {
  const biggerBoxRef = useRef(null);
  //드래그 영역으로 biggerBox 만큼 제한하려고 useRef 사용
  return (

<BiggerBox ref={biggerBoxRef}> // ref
  <Box variants={boxVariants} whileHover="hover" whileTap="click" />
    //variants 로 애니메이션 적용
  <Box whileHover={{ scale: 1.2, rotateZ: 90 }} whileTap={{ scale: 1, borderRadius: "100px" }} />
	// prop 직접 입력
  <Box drag dragConstraints={biggerBoxRef} whileDrag={{ backgroundColor: "rgba(255, 255, 255, 0.3)" }} />
	// biggerBox 영역만큼 드래그 가능. 드래그 하는 동안 색상 변화
</BiggerBox>

  );
}
profile
기록은 기억이 된다

0개의 댓글