Framer Motion チュートリアル: React アニメーションの作成はとても簡単です

React および Web 一般におけるアニメーションは、ページ上の UI 要素の視覚的な状態を時間の経過とともに変化させるプロセスです。視覚的なステータスとは何を意味しますか? 要素の外観に影響を与えるプロパティ: 高さ、形状、他の要素との相対的な位置など。アニメーションの中心的な考え方は、ページ上の何かの特定の目に見えるプロパティを時間の経過とともに変更するということです。

ここに画像の説明を挿入します
React でアニメーションを作成する方法はいくつかありますが、それらはすべて、CSS ルールを適用して視覚的な状態を変更する CSS アニメーションと、JavaScript を使用して要素のプロパティを変更する JavaScript アニメーションの 2 つの大きなカテゴリに分類されます。どちらのカテゴリでも、アニメーションを最初から実装することも、ライブラリを使用することもできます。CSS に関しては、CSS ルールを使用してアニメーションを合成したり、Animate.cssなどのサードパーティ ライブラリを使用したりできます。

JavaScript の使用を選択した場合は、カスタム コードを記述してアニメーションを作成したり、GSAP や Framer Motion などのライブラリを使用したりできます。各ライブラリにはそれぞれ利点があり、アニメーションを記述する方法もライブラリごとに異なります。この記事では、Framer デザイン チームによって作成および維持されている React アニメーション ライブラリであるFramer Motionについて説明します

すべての Framer Motion アニメーションを支えるコア コンポーネントを学び、Framer Motion を優れたツールにするいくつかの機能について洞察し、ライブラリを最大限に活用するためのベスト プラクティスを発見し、それをすべてステップで実践します。ステップごとの例。

始める前に、いくつかの基本的な知識が必要です。

  • React、HTML、CSS、JS の知識
  • コマンドラインとnpmの知識

React アニメーションの作成に Framer Motion を使用する理由は何ですか?

React プロジェクトで Framer Motion を検討する必要があるのはなぜですか? Framer Motion はかなり人気があり、積極的に維持されているライブラリであり、 Github上に 19,000 のスターがあり、それをサポートするリソースが大量にあります。

しかし最も重要なことは、Framer Motion は、複雑なプロダクション グレードのアニメーションを可能な限り少ないコードで作成できるようにするという考えに基づいて構築されていることです。Framer Motion の使用は非常に簡単で、コードを 1 行追加するだけでドラッグ アンド ドロップできます。Framer Motion は、SVG アニメーションやアニメーション レイアウト オフセットなどのタスクも大幅に簡素化します。

Framer Motion コンポーネントと API

Framer Motion はアニメーションに対する直感的なアプローチを採用しています。これは、マークアップをラップし、必要なアニメーションのタイプを指定できるように属性を受け入れるコンポーネントのセットを提供します。Framer Motion のコア コンポーネントには次のものが含まれます。

  • motionコンポーネント
  • AnimatePresenceコンポーネント

このmotionコンポーネントはすべてのアニメーションの基礎を提供します。React コンポーネントで HTML 要素をラップし、initialと に渡されたanimate状態を使用してそれらをアニメーション化します。以下に例を示します。Web 上のどこにでもある通常の 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このコンポーネントは と連動し、DOMmotionから削除する要素がページから削除される前に終了アニメーションを表示できるようにするために必要です。AnimatePresence次の 2 つの条件のいずれかを満たす直系の子にのみ適用されます。

  • 子はmotionコンポーネントでラップされます
  • 子には、motionその子の 1 つとしてコンポーネントでラップされた要素があります。

目的の終了アニメーションは、に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

多くのアニメーションに必要なのはこれら 2 つのコンポーネントだけですが、Framer Motion にはより複雑な使用を可能にする機能があります。motionこれらの機能の 1つは、ホバリング、タップ、ページ要素のドラッグなど、エンド ユーザーによるジェスチャに応じてコンポーネントがアニメーションをトリガーできるようにする、コンポーネント上の一連のプロパティです。これらのプロパティはジェスチャと呼ばれます。これは、ホバー ジェスチャの使用法を示す簡単な例です。

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

whileHoverプロパティはホバー ジェスチャです。上記のコードは、マウスを div の上に置くと div をフェードアウトし、マウスを離すと前の状態に戻します。

より大きな例を試す前に、最後の機能を見てみましょう。長さや遅延の調整など、アニメーションのさまざまな側面を調整したい場合、何を使用しますか? Framer Motion には、transitionこれらを指定できるプロパティが用意されています。Framer Motion では、 Spring アニメーションや Tween (イージングベース) アニメーションなど、さまざまなタイプのアニメーションを選択することもでき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;
}

次にヘッダーのコードです。srcHeader.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 アプリをブラウザーで表示すると、次のような Web ページが表示されるはずです。

フレーマーモーションアニメーションを追加

ベルのアイコンのアニメーションを開始します。ホバー時にトリガーされるリンギング モーションは、SVG アイコンを Z 軸に沿って最初に一方向に、次にもう一方の方向に回転し、その後通常に戻すことによって作成されます。

方法は次のとおりです:Header.jsx上部で importmotionAnimatePresence:

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

次に、Header.jsxSVG アニメーションを次のように追加します。

<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 秒継続することを指定します。

適用すると、Web ページ上にカーソルを置くとチャイム音が聞こえるはずです。

次に実装するアニメーションは、通知トレイ上のアイテムのフェードイン アニメーションです。作成しNotification.jsxてインポートし、motion次の操作を行いますAnimatePresence

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>をコンポーネントでラップし、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>

次に、NotificationTray.jsxこれをexit最も外側の div に追加します。

<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