프레이머 모션 튜토리얼: React 애니메이션 제작이 너무 쉽습니다

React와 일반적인 웹의 애니메이션은 시간이 지남에 따라 페이지에 있는 UI 요소의 시각적 상태를 변경하는 프로세스입니다. 시각적 상태는 무엇을 의미하나요? 요소의 모양에 영향을 미치는 모든 속성(높이, 모양, 다른 요소에 대한 상대적인 위치 등) 애니메이션의 핵심 아이디어는 시간이 지남에 따라 페이지에 있는 항목의 눈에 보이는 특정 속성을 변경한다는 것입니다.

여기에 이미지 설명을 삽입하세요.
React에서 애니메이션을 만드는 방법에는 여러 가지가 있지만 모두 크게 두 가지 범주, 즉 CSS 규칙을 적용하여 시각적 상태를 변경하는 CSS 애니메이션과 JavaScript를 사용하여 요소의 속성을 변경하는 JavaScript 애니메이션으로 분류됩니다. 두 범주 모두 처음부터 애니메이션을 구현하거나 라이브러리를 사용할 수 있습니다. CSS 측면에서 CSS 규칙을 사용하여 애니메이션을 합성하거나 Animate.css 와 같은 타사 라이브러리를 사용할 수 있습니다 .

JavaScript를 사용하기로 선택한 경우 사용자 정의 코드를 작성하여 애니메이션을 만들거나 GSAP 또는 Framer Motion과 같은 라이브러리를 사용할 수 있습니다. 각 라이브러리에는 장점이 있으며 각 라이브러리에는 애니메이션을 작성하는 방법이 다릅니다. 이 기사에서는 Framer 디자인 팀이 만들고 유지 관리하는 React 애니메이션 라이브러리인 Framer Motion을 살펴보겠습니다 .

모든 Framer Motion 애니메이션을 뒷받침하는 핵심 구성 요소를 배우고, Framer Motion을 훌륭한 도구로 만드는 일부 기능을 살펴보고, 라이브러리를 최대한 활용하기 위한 모범 사례를 발견하고, 단계별로 실행해 보겠습니다. 단계별 예시.

시작하기 전에 몇 가지 기본 지식이 필요합니다.

  • React, HTML, CSS 및 JS에 대한 지식
  • 명령줄 및 npm에 대한 지식

Framer Motion을 사용하여 React 애니메이션을 만드는 이유는 무엇입니까?

React 프로젝트에서 Framer Motion 사용을 고려해야 하는 이유는 무엇입니까? Framer Motion은 Github 에 19,000개의 별이 있고 이를 지원할 수 있는 많은 리소스가 있는 상당히 인기 있고 활발하게 유지 관리되는 라이브러리입니다 .

그러나 가장 중요한 것은 Framer Motion이 가능한 한 적은 코드로 복잡한 프로덕션급 애니메이션을 작성할 수 있다는 아이디어를 바탕으로 구축되었다는 것입니다. Framer Motion을 사용하는 것은 매우 쉽습니다. 코드 한 줄만 추가하면 드래그 앤 드롭이 가능합니다! Framer Motion은 또한 SVG 애니메이션 및 애니메이션 레이아웃 오프셋과 같은 작업을 크게 단순화합니다.

프레이머 모션 구성요소 및 API

Framer Motion은 애니메이션에 대한 직관적인 접근 방식을 가지고 있습니다. 원하는 애니메이션 유형을 지정할 수 있도록 마크업을 래핑하고 속성을 허용하는 구성 요소 집합을 제공합니다. Framer Motion의 핵심 구성 요소는 다음과 같습니다.

  • motion구성 요소
  • AnimatePresence구성 요소

motion구성 요소는 모든 애니메이션의 기초를 제공합니다. 이는 React 구성 요소의 HTML 요소를 래핑하고 및 initial에 전달된 animate상태를 사용하여 애니메이션을 적용합니다 . 아래는 예시입니다. 웹 어디에서나 찾을 수 있는 일반 div를 선택하세요.

<div>I have some content here</div>

이 div가 로드될 때 페이지에 페이드 인되도록 하려는 경우를 가정해 보겠습니다. 필요한 것은 다음 코드뿐입니다.

<motion.div
  initial={
     
     {
     
      opacity:0 }}
  animate={
     
     {
     
      opacity:1 }}
>
  I have some content in here 
</motion.div>

페이지가 로드되면 div는 투명에서 완전 불투명으로 부드럽게 애니메이션을 적용하고 점차적으로 페이지 속으로 사라집니다. 일반적으로 모션 컴포넌트를 설치할 때 initial지정된 값을 컴포넌트에 적용한 다음 animate지정된 값에 도달할 때까지 컴포넌트에 애니메이션을 적용합니다.

다음으로 살펴보겠습니다 AnimatePresence. 이 구성요소는 motionDOM에서 제거한 요소가 페이지에서 제거되기 전에 종료 애니메이션을 표시하도록 허용하는 데 필요합니다. AnimatePresence다음 두 가지 조건 중 하나를 충족하는 직계 자녀에게만 적용됩니다.

  • 자식은 motion구성 요소로 래핑 됩니다.
  • 자식에는 motion자식 중 하나로 구성 요소로 래핑된 요소가 있습니다.

exit 속성을 추가하여 원하는 종료 애니메이션을 지정해야 합니다 . motion예 는 다음과 같습니다 AnimatePresence.

<AnimatePresence>
  <motion.div
    exit={
     
     {
     
      x: "-100vh", opacity: 0 }}
  >
    Watch me go woosh!
  </motion.div>
</AnimatePresence>

래핑 AnimatePresencediv가 DOM에서 제거되면 사라지지 않지만 왼쪽으로 100vh 슬라이드되어 프로세스가 투명해집니다. 그 후에야 div가 페이지에서 제거됩니다. 여러 구성요소가 의 직계 하위인 경우 DOM에서 추적할 수 key있도록 모두 고유한 값을 가져야 합니다 .AnimatePresence

이 두 가지 구성 요소는 많은 애니메이션에 필요한 전부이지만 Framer Motion에는 보다 복잡한 용도를 허용하는 기능이 있습니다. 이러한 기능 중 하나는 구성 요소가 motion페이지 요소 가리키기, 클릭 또는 드래그와 같은 최종 사용자의 동작에 응답하여 애니메이션을 트리거할 수 있도록 하는 구성 요소의 속성 집합입니다. 이러한 속성을 제스처라고 합니다. 다음은 호버 동작 사용을 보여주는 간단한 예입니다.

<motion.div
  whileHover={
     
     {
     
     
    opacity: 0
  }}
>
  Hover over me and I'll disappear!
</motion.div>

whileHover속성은 호버 제스처입니다. 위 코드는 마우스를 div 위로 가져가면 div가 페이드 아웃되고 마우스가 멀어지면 이전 상태로 돌아갑니다.

더 큰 예를 시도하기 전에 마지막 기능을 살펴보겠습니다. 지속 시간이나 지연 조정 등 애니메이션의 다양한 측면을 조정하려면 무엇을 사용합니까? Framer Motion은 transition이를 지정할 수 있는 속성을 제공합니다. Framer Motion을 사용하면 Spring 애니메이션 과 Tween(easing 기반) 애니메이션 과 같은 다양한 유형의 애니메이션 중에서 선택할 수 있으며, transition속성을 통해 이를 제어할 수 있습니다. 예는 다음과 같습니다.

<motion.div
  initial={
     
     {
     
      opacity:0 }}
  animate={
     
     {
     
      opacity:1 }}
  transition={
     
     {
     
      duration: 0.5, delay: 0.1 }}
>
  I have some content here 
</motion.div>

이는 이전의 페이드인 애니메이션과 동일하지만 속성상 transition애니메이션이 시작되기까지 0.1초를 기다리고 0.5초 동안 지속됩니다.

Framer Motion을 사용하여 React 애플리케이션에서 애니메이션 구현

우리가 배운 모든 것을 활용하여 좀 더 복잡한 예를 만들어 봅시다. 이 기사가 끝나면 다음과 같은 애니메이션 알림 트레이가 만들어질 것입니다.

프로젝트 초기화

예제를 저장할 디렉터리로 이동하여 시작하세요. 그런 다음 터미널을 열고 다음 명령을 사용하여 Vite를 사용하여 시작 React 애플리케이션을 만듭니다.

npm create vite@latest

그런 다음 프롬프트에 다음과 같이 대답합니다.

여기에 이미지 설명을 삽입하세요.

이제 방금 생성한 프로젝트로 이동하여 을 실행 npm install하고 를 실행합니다 npm run dev. 이제 프로젝트 폴더는 다음과 같아야 합니다.

여기에 이미지 설명을 삽입하세요.

src/assets폴더와 를 삭제하고 App.css이제 애니메이션 없이 네비게이션 트레이를 코딩해 보세요. 프로젝트의 CSS부터 시작하여 index.css내용을 다음으로 바꿉니다.

:root {
    
    
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  font-weight: 400;
}
body {
    
    
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
  background-color: #fff;
  color: #111827;
}
header {
    
    
  height: 4rem;
  font-size: 1.1rem;
  border-bottom: 1px solid #e5e7eb;
  display: flex;
  align-items: center;
  padding: 0 2rem;
}
header > .header__left {
    
    
  width: 50%;
  font-size: 1.5rem;
}
header > .header__right {
    
    
  width: 50%;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  list-style-type: none;
  margin: 0;
  padding: 0;
}
.header__right > * {
    
    
  margin: 0 1.5rem;
  position: relative;
}
.header__right > .notification__button {
    
    
  height: 2rem;
  width: 2rem;
  cursor: pointer;
}
.header__right > .notification__icon {
    
    
  height: 100%;
  width: 100%;
}
.header__right > .image {
    
    
  border-radius: 50%;
  height: 3rem;
  width: 3rem;
  overflow: hidden;
}
.header__right > .image > img {
    
    
  height: 100%;
  width: 100%;
}
.notification__tray {
    
    
  border-radius: 6px;
  box-shadow: 0px 0px 8px #e5e7eb;
  position: fixed;
  width: 24rem;
  top: 4.5rem;
  right: 2rem;
  color: rgb(65, 65, 81);
  font-size: 0.875rem;
  line-height: 1.25rem;
}
.notification__tray > ul {
    
    
  list-style-type: none;
  margin: 0;
  padding: 0;
}
.notification__tray li {
    
    
  padding: 1rem 2rem;
  border-bottom: 1px solid #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: space-between;
}
.notification__tray li:hover {
    
    
  background-color: #e5e7eb;
  color: #111827;
}
.notification__tray li .clear__button {
    
    
  width: 1.5rem;
  height: 1.5rem;
  cursor: pointer;
}
.notification__tray li .clear__icon {
    
    
  width: 100%;
  height: 100%;
}
.todo__header {
    
    
  text-align: center;
}
.todo__container {
    
    
  list-style-type: none;
}
.todo__item {
    
    
  border: 1px solid #e5e7eb;
  border-radius: 5px;
  box-shadow: 0px 0px 8px #e5e7eb;
  color: #111827;
  margin: 1.5rem auto;
  width: 350px;
  padding: 1.5rem 2rem;
  background-color: #e5e7eb;
}

다음은 헤더에 대한 코드입니다. 에서 라는 파일을 src만들고 Header.jsx다음 내용으로 채웁니다.

import {
    
     useState } from "react";
import NotificationTray from "./NotificationTray";

const initialNotifications = [
  "User #20 left you a like!",
  "User #45 sent you a friend request",
  "Your song has been uploaded!",
  "Thanks for signing up!",
];

const Header = () => {
    
    
  const [showNotifications, setShowNotifications] = useState(false);
  const [notificationContent, setNotificationContent] =
    useState(initialNotifications);

  const handleDeleteNotification = (content) => {
    
    
    setNotificationContent(
      notificationContent.filter((item) => item !== content)
    );
  };

  return (
    <header>
      <div className="header__left">Brand</div>
      <ul className="header__right">
        <li
          className="notification__button"
          onClick={
    
    () => {
    
    
            setShowNotifications(!showNotifications);
          }}
        >
          <svg
            xmlns="http://www.w3.org/2000/svg"
            fill="none"
            viewBox="0 0 24 24"
            strokeWidth="1.5"
            stroke="currentColor"
            className="notification__icon"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5"
            />
          </svg>
        </li>
        <li className="image">
          <img src="https://www.dummyimage.com/48x48" />
        </li>
      </ul>

      {
    
    showNotifications ? (
        <NotificationTray
          notificationContent={
    
    notificationContent}
          handleDeleteNotification={
    
    handleDeleteNotification}
        ></NotificationTray>
      ) : null}
    </header>
  );
};
export default Header;

간결성을 위해 시작 코드에 대해 자세히 설명하지는 않지만 기본적으로 몇 가지 작업을 수행합니다.

  • 알림 트레이 구성요소 가져오기
  • 트레이에 대한 상태를 생성하고 상태에서 알림을 제거하는 도우미 함수를 정의합니다.
  • 헤더용 마크업 생성 및 조건부 렌더링 트레이

다음으로 알림 트레이 구성 요소에 대한 코드를 작성합니다. 이라는 파일을 만들고 NotificationTray.jsx다음 코드를 입력하세요.

const NotificationTray = ({
    
    
  notificationContent,
  handleDeleteNotification,
}) => {
    
    
  return (
    <div className="notification__tray">
      <ul>
        {
    
    notificationContent.map((content) => {
    
    
          return (
            <li key={
    
    content}>
              <span>{
    
    content}</span>
              <span
                className="clear__button"
                onClick={
    
    () => {
    
    
                  handleDeleteNotification(content);
                }}
              >
                <svg
                  xmlns="http://www.w3.org/2000/svg"
                  fill="none"
                  viewBox="0 0 24 24"
                  strokeWidth={
    
    1.5}
                  stroke="currentColor"
                  className="clear__icon"
                  title="Clear notification"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
                  />
                </svg>
              </span>
            </li>
          );
        })}
      </ul>
    </div>
  );
};
export default NotificationTray;

이 코드:

  • 트레이의 상태를 각각 에 대한 알림과 함께 표시합니다 <ul>.<li>
  • Header.jsx지우기 버튼을 클릭하면 프로그램 기능을 사용하여 알림을 삭제합니다.

마지막으로 헤더를 다음과 같이 렌더링합니다 App.jsx.

import Header from "./Header"

function App() {
    
    
  return (
    <>
      <Header></Header>
    </>
  )
}
export default App

이 모든 내용에는 알림 트레이가 제대로 작동하도록 하는 데 필요한 코드가 포함됩니다. 브라우저에서 React 앱을 보면 다음과 같은 웹 페이지가 있어야 합니다.

프레이머 모션 애니메이션 추가

벨 아이콘 애니메이션을 시작하겠습니다. 호버 시 트리거되는 벨소리 동작은 SVG 아이콘을 z축을 따라 처음에는 한 방향으로 회전한 다음 다른 방향으로 회전한 다음 다시 정상으로 되돌림으로써 생성됩니다.

방법은 다음과 같습니다. Header.jsx상단에서 가져오기 motion및 다음을 수행합니다 AnimatePresence.

import {
    
    motion, AnimatePresence} from "framer-motion";

그런 다음 다음 Header.jsx에 SVG 애니메이션을 추가하십시오.

<motion.svg
  whileHover={
     
     {
     
     
    rotateZ: [0, -20, 20, -20, 20, -20, 20, 0],
    transition: {
     
      duration: 0.5 },
  }}
  xmlns="http://www.w3.org/2000/svg"
  fill="none"
  viewBox="0 0 24 24"
  strokeWidth="1.5"
  stroke="currentColor"
  className="notification__icon"
>
  <path
    strokeLinecap="round"
    strokeLinejoin="round"
    d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5"
  />
</motion.svg>

SVG가 변경되는 방법은 다음과 같습니다.

  • 그것은 감싸다motion
  • 속성으로 제스처가 있으므로 whileHover애니메이션은 SVG 호버에서만 실행됩니다.
  • 에 전달된 객체 에서 whileHover배열의 값 범위를 지정합니다. 이 배열을 키프레임이라고 합니다. 이는 Framer Motion이 키프레임에 지정된 각 값으로 SVG에 애니메이션을 적용하지 않음을 의미합니다.
  • 에 전달된 객체에서 transition애니메이션이 0.5초 동안 지속되도록 지정합니다.

적용한 후에는 웹 페이지 위로 마우스를 가져갈 때 차임 소리가 표시됩니다.

구현할 다음 애니메이션은 알림 트레이의 항목에 대한 페이드인 애니메이션입니다. 다음을 생성 Notification.jsx하고 가져옵니다 .motionAnimatePresence

import {
    
     motion, AnimatePresence } from "framer-motion";

div그런 다음 외부 코드를 다음과 같이 수정합니다.

<motion.div
  className="notification__tray"
  initial={
     
     {
     
      opacity: 0 }}
  animate={
     
     {
     
      opacity: 1 }}
>
  <ul>
    .....
  </ul>
</motion.div>

변경되는 모든 것은 div가 0에서 시작하고 애니메이션이 완전히 표시되도록 및 props의 값을 설정한다는 div것 입니다. Return 이를 반복 하고 다음과 같이 0.2초의 지속 시간을 추가합니다.motion.divinitialanimateopacity<li>map

{
    
    
  notificationContent.map((content) => {
    
    
    return (
      <motion.li
        key={
    
    content}
        initial={
    
    {
    
     opacity: 0 }}
        animate={
    
    {
    
     opacity: 1 }}
        transition={
    
    {
    
     duration: 0.2 }}
      >
        ...
      </motion.li>
    )
  })
}

추가 터치로 각 알림의 종료에 애니메이션을 적용해 보겠습니다. 트레이에서 제거할 때 슬라이드 애니메이션을 추가하면 li됩니다 . 지금 해야 할 일은 <li>s를 구성 요소로 래핑한 다음 props를 사용하여 exit각 구성 요소가 제거될 <li>AnimatePresence어떤 일이 발생하는지 지정하는 것입니다. 어떻게 작동하는지 살펴보겠습니다.

<ul>
  <AnimatePresence>
    {notificationContent.map((content) => {
      return (
        <motion.li
          key={content}
          initial={
     
     {
     
      opacity: 0 }}
          animate={
     
     {
     
      opacity: 1 }}
          exit={
     
     {
     
      x: "-12rem", opacity: 0 }}
          transition={
     
     {
     
      duration: 0.2 }}
          layout
        >
          ....
        </motion.li>
      )
    })}
  </AnimatePresence>
</ul>

exit속성에 따르면 제거되면 <li>왼쪽으로 12rem(트레이 너비의 절반) 이동한 다음 언로드 전에 사라져야 합니다. layout속성은 Framer Motion에게 레이아웃 오프셋으로 인해 발생하는 요소 위치의 변경 사항을 애니메이션으로 표시하도록 지시합니다. 이는 a가 트레이에서 제거될 때 <li>형제가 공간을 채우기 위해 점프하는 대신 새 위치로 부드럽게 미끄러진다는 것을 의미합니다. 시간을 내어 직접 확인해 보세요.

이 섹션의 마지막 작업은 트레이 출구(종을 클릭한 후 트레이가 사라질 때)를 애니메이션하는 것입니다. 적용할 애니메이션 <li>: 왼쪽으로 스와이프하고 페이드 아웃하는 것과 동일한 종료 애니메이션입니다.

구성 요소를 반환 Header.jsx하고 다음으로 AnimatePresence래핑합니다 .NotificationTray

<AnimatePresence>
  {showNotifications ? (
    <NotificationTray
      notificationContent={notificationContent}
      handleDeleteNotification={handleDeleteNotification}
    ></NotificationTray>
  ) : null}
</AnimatePresence>

그런 다음 가장 바깥쪽 div에 NotificationTray.jsx다음을 추가합니다 .exit

<motion.div
  className="notification__tray"
  initial={
     
     {
     
      opacity: 0 }}
  animate={
     
     {
     
      opacity: 1 }}
  exit={
     
     {
     
      opacity: 0, x: "-12rem" }}
>
  <ul>...</ul>
</motion.div>

이것으로 애니메이션의 기초가 완성되었습니다! 이제 트레이에 다음과 같은 애니메이션이 표시됩니다.

추천

출처blog.csdn.net/jslygwx/article/details/132662650