Анимация навигации с помощью Framer Motion

У меня проблема с анимацией панели навигации. Я использую React и Framer Motion. Мой результат почти готов, но его еще нужно немного доработать, чтобы сделать его идеальным до пикселя. У меня проблемы с анимацией ссылок; они должны быть заблокированы слева, но мои задвигаются справа. Они также должны раскрываться слева направо, один за другим. Не могли бы вы проверить мой код и предложить некоторые улучшения для достижения желаемого результата? Вот короткое видео о том, как это должно анимироваться: https://www.loom.com/share/d882818c384e4af18abeabf92abb2980


import Link from "next/link";
import React, { useState } from "react";
import HamburgerIcon from "./icons/HamburgerIcon";
import { motion } from "framer-motion";

const MenuDesktop = () => {
  const [isHovered, setIsHovered] = useState(false);

  const navVariants = {
    initial: { width: "5rem", opacity: 0, zIndex: 0 },
    hover: { width: "100%", opacity: 1, zIndex: 1 },
  };

  const linkVariants = {
    initial: { opacity: 0 },
    hover: { opacity: 1 },
  };

  const iconVariants = {
    initial: { opacity: 1 },
    hover: { opacity: 0 },
  };

  return (
    <div className = "flex p-0.5 h-20 rounded-15px bg-cc-invert justify-center items-stretch overflow-hidden">
      <div className = "relative">
        <motion.nav
          className = "flex relative h-full overflow-auto"
          initial = "initial"
          animate = {isHovered ? "hover" : "initial"}
          variants = {navVariants}
          transition = {{
            width: { duration: 0.75, ease: "easeInOut" },
            opacity: { duration: 1, ease: "easeInOut" },
          }}
          onHoverStart = {() => setIsHovered(true)}
          onHoverEnd = {() => setIsHovered(false)}
        >
          <motion.div
            className = "font-dmMono tracking-wider text-cc-dark-brown flex items-center gap-2 text-xs uppercase pl-4 bg-cc-invert "
            initial = "initial"
            animate = {isHovered ? "hover" : "initial"}
            variants = {linkVariants}
            transition = {{ duration: 0.5 }}
          >
            <Link className = "px-2 whitespace-nowrap" href = "/development">
              Development
            </Link>
            <Link className = "px-2 whitespace-nowrap" href = "/energo">
              Energo
            </Link>
            <Link className = "px-2 whitespace-nowrap" href = "/company">
              Company
            </Link>
            <Link className = "px-2 whitespace-nowrap" href = "/news">
              News
            </Link>
            <Link className = "px-2 whitespace-nowrap" href = "/career">
              Career
            </Link>
          </motion.div>
        </motion.nav>
        <motion.div
          className = "absolute top-7 right-7 flex items-center cursor-pointer z-0"
          initial = "initial"
          animate = {isHovered ? "hover" : "initial"}
          variants = {iconVariants}
          transition = {{ duration: 0.5 }}
        >
          <HamburgerIcon className = "h-5 cursor-pointer" />
        </motion.div>
      </div>
      <Link
        href = "/"
        className = "font-dmMono tracking-wider text-cc-dark-brown flex items-center justify-center p-4 bg-cc-light-brown rounded-15px"
      >
        <span className = "uppercase text-xs px-2">Contact</span>
      </Link>
    </div>
  );
};

export default MenuDesktop;
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
0
0
99
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Нужную анимацию можно получить с помощью свойства staggerChildren в Framer Motion. Это свойство позволяет задерживать анимацию прямых дочерних элементов.

import Link from "next/link";
import React, {
  useState
} from "react";
import HamburgerIcon from "./icons/HamburgerIcon";
import {
  motion
} from "framer-motion";

const MenuDesktop = () => {
  const [isHovered, setIsHovered] = useState(false);

  const navVariants = {
    initial: {
      width: "5rem",
      opacity: 0,
      zIndex: 0
    },
    hover: {
      width: "100%",
      opacity: 1,
      zIndex: 1
    },
  };

  const linkContainerVariants = {
    initial: {
      opacity: 0
    },
    hover: {
      opacity: 1,
      transition: {
        staggerChildren: 0.1,
        delayChildren: 0.2
      }
    },
  };

  const linkVariants = {
    initial: {
      x: -50,
      opacity: 0
    },
    hover: {
      x: 0,
      opacity: 1
    },
  };

  const iconVariants = {
    initial: {
      opacity: 1
    },
    hover: {
      opacity: 0
    },
  };

  return ( <
    div className = "flex p-0.5 h-20 rounded-15px bg-cc-invert justify-center items-stretch overflow-hidden" >
    <
    div className = "relative" >
    <
    motion.nav className = "flex relative h-full overflow-auto"
    initial = "initial"
    animate = {
      isHovered ? "hover" : "initial"
    }
    variants = {
      navVariants
    }
    transition = {
      {
        width: {
          duration: 0.75,
          ease: "easeInOut"
        },
        opacity: {
          duration: 1,
          ease: "easeInOut"
        },
      }
    }
    onHoverStart = {
      () => setIsHovered(true)
    }
    onHoverEnd = {
      () => setIsHovered(false)
    } >
    <
    motion.div className = "font-dmMono tracking-wider text-cc-dark-brown flex items-center gap-2 text-xs uppercase pl-4 bg-cc-invert "
    initial = "initial"
    animate = {
      isHovered ? "hover" : "initial"
    }
    variants = {
      linkContainerVariants
    } >
    {
      ["Development", "Energo", "Company", "News", "Career"].map((link) => ( <
        motion.div variants = {
          linkVariants
        }
        transition = {
          {
            duration: 0.5
          }
        } >
        <
        Link className = "px-2 whitespace-nowrap"
        href = {
          `/${link.toLowerCase()}`
        } > {
          link
        } <
        /Link> <
        /motion.div>
      ))
    } <
    /motion.div> <
    /motion.nav> <
    motion.div className = "absolute top-7 right-7 flex items-center cursor-pointer z-0"
    initial = "initial"
    animate = {
      isHovered ? "hover" : "initial"
    }
    variants = {
      iconVariants
    }
    transition = {
      {
        duration: 0.5
      }
    } >
    <
    HamburgerIcon className = "h-5 cursor-pointer" / >
    <
    /motion.div> <
    /div> <
    Link href = "/"
    className = "font-dmMono tracking-wider text-cc-dark-brown flex items-center justify-center p-4 bg-cc-light-brown rounded-15px" >
    <
    span className = "uppercase text-xs px-2" > Contact < /span> <
    /Link> <
    /div>
  );
};

export default MenuDesktop;

Другие вопросы по теме

Похожие вопросы

Как визуализировать сноски с отсутствующими определениями, используя реакции-уценку и примечание-gfm
Css работает локально, но не применяется после запуска «npm run build» в сборке в приложении реагирования
Правильный способ повторить тестовую логику в Cypress с динамическим повторным рендерингом DOM
Django, React, Axios возвращают html вместо данных json
Как предварительно настроить базовую анимацию движения кадра в полиморфном компоненте, использующем слот Radix?
Почему PWA на основе реагирования, размещенное в моей службе приложений Azure, случайно начинает возвращать ошибку 500 для ВСЕХ вызовов POST (GET работает нормально)? Исправлено: Перезапустить браузер?
Не могу найти способ сделать условные реквизиты
Есть ли способ визуализировать HTML из строки в React без использования dangerouslySetInnerHTML или пакета React HTML Parser?
Ошибка теста Playwright: реквизиты возвращают разные значения в пользовательском интерфейсе тестирования Playwright и в реальном приложении React в браузере Chrome
TypeScript › Обновление импорта при перемещении файла: включено, не работает в VS Code