ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Framer Motion] animation의 최강자 Framer Motion 알아보기, Animation/Variants/Gestures/Drag
    프론트엔드 개발자가 될거야./라이브러리 2023. 1. 8. 20:11

    Framer Motion는 Framer가 제공하는 리액트용 애니메이션 라이브러리이다.

    Framer Motion을 잘 이용한다면 Drag이벤트, Scroll이벤트 등 다양한 애니메이션들을 쉽게 표현해 낼 수 있다.

     

    노마드코더 리액트 마스터를 통해 접할 수 있었는데

    CSS로 했었으면 코드를 몇시간동안 고민고민해서 써야지 구현되는 효과들이

    단 한줄로 구현되는 것을 보고 정말 놀라웠다...

     

    아래는 Framer Motion 사이트이다. 여러 docs들도 있으니 보고 참고해도 좋을 것 같다. 

    https://www.framer.com/motion/

     

    Production-Ready Animation Library for React | Framer Motion

    Framer Motion is a production-ready React animation and gesture library.

    www.framer.com

     


    <다운로드 및 간단한 사용법>

    다운로드는 다른 라이브러리와 똑같이

    npm i framer-motion

    하면 되고

     

    framer-motion으로 애니메이션을 하길 원한다면

    <motion.div> aaaaa </motion.div>
    <motion.span> bbbbb </motion.span>

    이처럼 motion 패키지로부터 나와야 한다.

     

    styled-component와 쓰고싶다면

    const Box = styled(motion.div)`
      width: 200px;
      height: 200px;
      background-color: white;
      border-radius: 10px;
      box-shadow: 0 2px 3px rgba(0, 0, 0, 0.1), 0 10px 20px rgba(0, 0, 0, 0.06);
    `;

    이처럼 괄호안에서 써서 사용하면 된다.

     

    그리고 return문 안에서 적절한 곳에 Prop을 집어넣으면 된다!

    function App() {
      return (
        <Wrapper>
          <Box transition={{ duration: 3 }} animate={{ borderRadius: "100px" }} />
        </Wrapper>
      );
    }

    <Animation>

     

    위 영상처럼 처음에는 엄청 작다가 점점 커지는 animation을 구현해보려고 한다.

    <Box
      transition={{ type: "spring", delay: 1 }}
      initial={{ scale: 0 }} // 애니메이션 초기 스티일
      animate={{ scale: 1, rotateZ: 360 }} // 최종 스타일
    />

    원하는 요소에 초기 스타일인 initial최종 스타일인 animate을 주고
    transition으로 원하는 효과를 주면 끝이다!

    https://www.framer.com/docs/transition/

     

    Transition | Framer for Developers

    A transition defines how values animate from one state to another.

    www.framer.com

    다양한 효과가 있으니 위의 링크를 참고하여 무슨 효과를 줄지 정해보면 된다 : )

     

    또한 구조적인 코드를 짜기위해 위의 코드를 variants로 관리 할 수 있다.

    const myVars = {
      start: { scale: 0 },
      end: { scale: 1, rotateZ: 360, transition: { type: "spring", delay: 1 } },
    };
    
    function App() {
      return (
        <Wrapper>
          <Box variants={myVars} initial="start" animate="end" />
        </Wrapper>
      );
    }

     

    variants={myVars}로 어디에 variants가 있는지 알려주고

    initial="start"로 initial variants의 이름이 뭔지 알려주고

    animate="end"로 finishing variants의 이름이 뭔지 알려주면 끝!

     


    <Variants>

     

    위의 영상이 처음에는 큰 정사각형이 나오고 크 후 각각 원들이 나오는 것 처럼

    variants는 많은 애니메이션들을 하나로 연결시켜준다.

     

    이처럼 부모 컴포넌트가 있고 부모 컴포넌트에 initial이름과 animate이름이 있고 variants가 있을 때

    variants은 기본값으로 부모의 initial이름과 animate이름을 (start와 end를) 그 자식들에게 복붙해준다.

     

    중요한 것은 자식에게 따로 효과를 주고싶을 때

    부모에서 준 initial이름과 animate이름을 똑같이 해줘야한다는 것이다.

    (부모의 initial과 animate을 상속하기 때문!)

     

    예를들어

    부모요소 Box가 있고 자식요소 Circle가 있을 때

    부모요소 Box의 variants={boxVariants} initial="start" animate="end"를

    자식요소 Circle에게 쓰지 않아도 Circle에게 상속이 된다!

     

    그러니 Circle에게 따로 효과를 주고싶을 때 

    circleVariants에서 볼 수 있는 것 처럼 부모요소와 같은 initial이름과 animate이름을 적용해야한다.

     

    delayChildren자식들을 기다리게 하는 효과이고

    staggerChildren자식들에게 시간차로 딜레이를 주는 효과이다. 

    staggerChildren만 해주면 어떠한 복잡한 계산도 안해줘도 되기 때문에 매우 편리하다.

    const boxVariants = {
      start: {
        opacity: 0,
        scale: 0.5,
      },
      end: {
        scale: 1,
        opacity: 1,
        transition: {
          type: "spring",
          duration: 0.5,
          bounce: 0.5,
          delayChildren: 0.5,
          staggerChildren: 0.3,
        },
      },
    };
    
    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>
      );
    }

    <Gestures / Drag>

    Gestures

     

    Gestures는 이벤트를 listen 하는 것이다.

    예를들어 whileHover는 호버이벤트,  whileTap는 클릭이벤트이다.

    const circleVariants = {
      hover: { scale: 1.5, rotateZ: 90 },
      click: { scale: 1, borderRadius: "100px" },
    };
    
    function App() {
      return (
        <Wrapper>
          <Box variants={circleVariants} whileHover="hover" whileTap="click" />
        </Wrapper>
      );
    }

    이렇게 쓸 수 있다 : )

     

    Drag

     

    Drag는 드래깅을 활성화한다.

    <Box drag variants={circleVariants} whileHover="hover" whileTap="click" />

    그런데 드래그이벤트를 주고

    backgroundColor: "blue" 이런식으로 값을 주면 애니메이션을 할 수 없다.

    backgroundColor: "rgba(46,204,113)" 이렇게 숫자값을 줘야 애니메이션이 된다.

     

    - Gestures / Drag 코드정리

    const circleVariants = {
      hover: { scale: 1.5, rotateZ: 90 },
      click: { scale: 1, borderRadius: "100px" },
      drag: { backgroundColor: "rgb(46, 204, 113)", transition: { duration: 10 } },
    };
    
    function App() {
      return (
        <Wrapper>
          <Box
            drag
            variants={circleVariants}
            whileHover="hover"
            whileTap="click"
            whileDrag="drag"
          />
        </Wrapper>
      );
    }

     

     Drag 제약

    Drag에 제약을 줄 수 있다.

     

    예를들어 스크롤을 잠가버릴 수 있는데

    drag=”x” 는 x축으로만 이동 가능,  drag=”y” 는 y축으로만 이동 가능하다.

    그리고

    dragConstraints={{ top: -50, bottom: 50, left: -50, right: 50 }} 는 드래깅이 허용될 수 있는 영역 Box를 만들 수 있다.

    dragSnapToPrigin는 중앙으로 되돌아오게하는 힘이 생기게 해준다.

    dragElastic는 0과 1 사이의 값이어야 하고 1이면 어디든지 갈 수 있다.(“당기는 힘” 같은 게 있다는 의미!)

     

    const biggerBoxRef = useRef<HTMLDivElement>(null)는 useRef로 움직일 수 있는 영역을 잡아준다!

    const boxVariants = {
      hover: { rotateZ: 90 },
      click: { borderRadius: "100px" },
    };
    
    function App() {
      const biggerBoxRef = useRef<HTMLDivElement>(null);
      return (
        <Wrapper>
          <BiggerBox ref={biggerBoxRef}>
            <Box
              drag
              dragSnapToOrigin
              dragElastic={0.5}
              dragConstraints={biggerBoxRef}
              variants={boxVariants}
              whileHover="hover"
              whileTap="click"
            />
          </BiggerBox>
        </Wrapper>
      );
    }

    댓글

Designed by Tistory.