首页 > 其他分享 >如何使用React和Framer Motion构建图像轮播

如何使用React和Framer Motion构建图像轮播

时间:2023-07-04 10:37:11浏览次数:49  
标签:React const 轮播 动画 index Motion 图像 我们

您可能在许多现代应用程序中遇到过轮播。这些多功能网页元素以各种名称(例如滑块或旋转器)而闻名,它们以视觉上吸引人的滑动或旋转方式展示内容。

轮播可以帮助您节省空间、增强用户界面并提供出色的用户体验。

轮播已成为 UI 设计的主要内容,通常用于显示图像、推荐等。创建引人入胜的动态界面时,它们是不可或缺的。

在本文中,我们将深入探讨使用 React 和 Framer Motion 构建图像轮播的过程,指导您完成每一步,为您的应用程序创建令人惊叹的交互式视觉组件。

(更|多优质内|容:java567 点 c0m)

 

什么是成帧器运动?

这是一个用于 React 应用程序的开源动画库,您可以使用它为我们的 Web 应用程序创建动态和响应式动画。

Framer Motion 有几个有用的功能,包括:

  1. 动画:这允许您为组件进行无缝过渡。

  2. 手势:它支持触摸和鼠标动作,允许您考虑某些事件。

  3. 变体:Framer Motion 使您能够以声明方式声明组件,从而保持代码的组织性和可重用性。

所有这些功能都非常有用,我们很快就会看到它们的实际应用。

要更深入地了解 Framer Motion,您可以浏览其文档和资源。但在本文中,我们将重点关注基础知识。当我指导您了解使用 Framer Motion 的基础知识时,我的主要目标是构建令人印象深刻且引人入胜的图像轮播。

如何设置您的开发环境

我们要做的第一件事是设置您的开发环境。这涉及安装必要的包以成功构建您的应用程序。这包括安装Node.js和npm

如果您已经安装了 Node.js 和 npm,则无需再次下载并安装它们。

创建一个 React 应用程序

此时,我假设您已经安装了 Node 和 npm。要创建 React 应用程序,只需转到终端并访问您希望应用程序所在的目录。然后运行以下命令:

 npx create-react-app react-image-carousel

您可以为您的应用程序命名任何您想要的名称 - 但出于本文的目的,我将其命名为react-image-carousel.

成功创建 React 应用程序后,在代码编辑器中打开您的目录。您应该获得一些默认文件和样式,它应该如下所示:

 

我们不需要此项目中的大部分文件和样式,因此您可以清理以下文件:app.test.js、logo.svg、reportWebVitals.js、setupTest.js。您还可以删除 App.css 表中的所有默认样式。

 

现在您的 React 应用程序已创建并设置完毕,为此项目设置开发环境的最后一步是安装 Framer Motion。

为此,只需转到终端确保您位于项目目录中并运行以下命令:

  npm  install framer-motion

这应该安装最新版本的 Framer Motion。现在你应该可以走了。只需用于npm run start在浏览器上启动开发服务器即可。

如何设计图像轮播组件

为了开始设计,我们首先创建一个Carousel.js组件。在轮播组件中,我们将从useStateReact 导入钩子,然后从 Framer Motion导入motion和属性。AnimatePresence

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

然后我们创建 carousel 函数,该函数接受imagesprop,该 prop 是图像 URL 的数组:

 const Carousel = ({ images }) => {};

在我们的 carousel 函数中,我们使用 useState 初始化一个状态变量,以跟踪我们用作setCurrentIndex更新索引的相应函数的当前图像索引。

接下来,我们创建 3 个辅助函数来处理用户交互,其中包括:

  • handleNext:这会将 currentIndex 更新为下一个索引,以便更改图像,如果到达数组末尾,则循环返回。

  • handlePrevious:这与handleNext 函数的作用相同,但这次顺序相反。这使我们能够回到图像。

  • handleDotClick:这将索引作为参数并更新 currentIndex。这样,我们只需单击这些点就可以向前和向后跳转到图像。

 const Carousel = ({ images }) => {
   const [currentIndex, setCurrentIndex] = useState(0);
 ​
   const handleNext = () => {
     setCurrentIndex((prevIndex) =>
       prevIndex + 1 === images.length ? 0 : prevIndex + 1
    );
  };
   const handlePrevious = () => {
     setCurrentIndex((prevIndex) =>
       prevIndex - 1 < 0 ? images.length - 1 : prevIndex - 1
    );
  };
   const handleDotClick = (index) => {
     setCurrentIndex(index);
  };

这些是我们的组件所需的辅助函数

如何创建我们的模板

我们的模板非常简单,由图像、滑块方向和点(指示器)组成。

   return (
     <div className="carousel">
         <img
           key={currentIndex}
           src={images[currentIndex]}
         /><div className="slide_direction">
         <div className="left" onClick={handlePrevious}>
           <svg
             xmlns="/2000/svg"
             height="20"
             viewBox="0 96 960 960"
             width="20"
           >
             <path d="M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z" />
           </svg>
         </div>
         <div className="right" onClick={handleNext}>
           <svg
             xmlns="/2000/svg"
             height="20"
             viewBox="0 96 960 960"
             width="20"
           >
             <path d="m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z" />
           </svg>
         </div>
       </div>
       <div className="indicator">
        {images.map((_, index) => (
           <div
             key={index}
             className={`dot ${currentIndex === index ? "active" : ""}`}
             onClick={() => handleDotClick(index)}
           ></div>
        ))}
       </div>
     </div>
  );

正如您在模板中看到的,我们在当前索引处显示图像。然后我们有一个 div,其中包含两个带有类名和 的slider_directiondiv 。我们将它们创建为轮播的导航按钮。它们使用内联 SVG 来显示箭头图标,并且它们的 onClick 处理程序分别设置为和。leftrighthandlePrevious``handleNext

我们还有一个指示器 div,我们创建它来显示代表轮播中每个图像的一系列点。它映射图像数组并为每个图像创建一个点,为与currentIndex.

然后,我们为每个点附加一个 onClick 处理程序,该处理程序设置handleDotClick为使用点的索引进行调用。

现在这应该是我们的模板。剩下的就是导出 carousel 组件,将其导入到App.js组件中,并添加一些 CSS。然后我们就准备开始制作动画了。

因此,我们只需从组件中导出轮播功能即可Carousel.js。

 export default Carousel;

如何使用轮播组件

我们已经创建了轮播组件。但要使用它,我们必须将其导入到我们的 App.js 组件中:

 import Carousel from "./Carousel";

之后,我们可以创建图像数组,它将保存我们的图像 URL。

 const images = [
   "/photos/169647/pexels-photo-169647.jpeg?auto=compress&cs=tinysrgb&w=600",
   "/photos/313782/pexels-photo-313782.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
   "/photos/773471/pexels-photo-773471.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
   "/photos/672532/pexels-photo-672532.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
   "/photos/632522/pexels-photo-632522.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
   "/photos/777059/pexels-photo-777059.jpeg?auto=compress&cs=tinysrgb&w=1260&h=750&dpr=1",
 ];

这些只是我从pexels获得的图像- 这就是我们将在这个项目中使用的图像。

接下来,我们添加 App 函数,它将保存我们的应用程序模板。

 function App() {
   return (
     <div className="App">
       <header className="App-header">
         <h1>Image Carousel using React and Framer Motion</h1>
       </header>
       <main>
         <Carousel images={images} />
       </main>
     </div>
  );
 }
 export default App;

正如您所看到的,我们的标题仅显示一个标题,显示我们的应用程序的内容。

然后我们有主要部分,其中添加了轮播组件并接受图像数组的道具。如果您还记得,这是我们在轮播组件中用于显示图像的道具。

最后,我们导出 App 组件,以便我们可以在 index.js 文件中使用它。

要在没有样式的情况下查看所有这些,请运行命令npm run start。该应用程序应如下所示:

 

丑陋吧?是的,我同意你的看法。但只需几行 CSS,这一切就会发生转变。那么让我们深入了解一下吧。

如何添加 CSS

我不想为轮播组件创建单独的样式表,因此我们将在 App.css 文件中完成所有 CSS 操作。不要忘记导入样式表。

 import "./App.css"

这是我们的 CSS:

 @import url("/css2?family=Oswald:wght@600&display=swap");
 .App-header {
   font-size: 1rem;
   text-align: center;
   font-family: "Oswald", sans-serif;
   padding-bottom: 2rem;
 }
 .carousel-images {
   position: relative;
   border-radius: 10px;
   height: 400px;
   max-width: 650px;
   margin: auto;
   overflow: hidden;
 }
 .carousel-images img {
   width: 99%;
   height: 99%;
   border-radius: 8px;
   border: #ff00008e solid 2px;
 }
 .slide_direction {
   display: flex;
   justify-content: space-between;
 }
 .left,
 .right {
   background-color: #fb666675;
   color: #fff;
   padding: 10px 8px 8px 13px;
   margin: 0 20px;
   border-radius: 50%;
   position: absolute;
   top: 0;
   bottom: 0;
   margin: auto 10px;
   height: 25px;
   width: 25px;
 }
 .left {
   left: 0;
 }
 .right {
   right: 0;
 }
 .carousel-indicator {
   margin-top: 20px;
   display: flex;
   justify-content: center;
   gap: 20px;
 }
 .dot {
   background-color: #333;
   width: 15px;
   height: 15px;
   border-radius: 50%;
 }
 .active {
   background-color: #fa2020;
 }

这是我们的 CSS 的结果:

 

您可能会同意,这看起来好多了,而且功能已经齐全。

现在让我们继续使用 Framer Motion 添加动画,使其具有漂亮的滑动外观。

如何向轮播组件添加动画

要开始使用 Framer Motion 制作动画,您必须熟悉一些概念,因为我们将在本节中经常使用它们。这些概念包括:

  • 变体:将变体视为一组命名的属性。它的工作是定义元素应该如何显示或动画。您可以创建不同的变体来表示元素的不同视觉状态或动画,例如open、closed、hover等。

  • 初始状态:这就是动画开始之前对象所具有的状态。

  • 动画:这只是你的对象将要动画的状态,就这么简单。

回到项目,我们将动画添加到轮播组件中。我们已经导入了我们需要的两个属性 -motion和AnimatePresence属性。

我将把本节分为三个部分,因为我们将向代码的三个部分添加动画,包括图像、滑块方向和指示点。

图像动画

为了对图像的退出和进入进行动画处理,我们需要用一个 组件来包装我们的img元素。AnimationPresence这使我们能够在图像离开或进入时添加动画。然后我们motion.像这样将 a 附加到我们的标签上。

  <AnimatePresence>
   <motion.img key={currentIndex} src={images[currentIndex]} />
 </AnimatePresence>;

接下来,我们走出模板并声明我们的变体。

   const slideVariants = {
     hiddenRight: {
       x: "100%",
       opacity: 0,
    },
     hiddenLeft: {
       x: "-100%",
       opacity: 0,
    },
     visible: {
       x: "0",
       opacity: 1,
       transition: {
         duration: 1,
      },
    },
     exit: {
       opacity: 0,
       scale: 0.8,
       transition: {
         duration: 0.5,
      },
    },
  };

如您所见,sliderVariants具有四个属性:

  • hiddenRight:这会将图像的不透明度设置为 0 并将其放置在容器的右侧。

  • hiddenLeft:这与hiddenRight 的作用相同,但这次它设置在左侧。

  • 可见:无论图像位于容器中心的哪个位置,都会调用此属性来实现幻灯片动画。

  • exit:此动画控制当另一个图像滑入时从屏幕上删除图像。

现在我们的变体已经设置好了。我们如何知道图像应该从哪里滑入?我们需要设置一个方向状态并根据slide_direction单击的 s 来更新状态。

   const [direction, setDirection] = useState('left');

所以我们将方向设置为从左侧开始。这只是合乎逻辑的,因为要显示的第一幅图像将是第一幅图像。然后我们转到辅助函数并根据单击的方向设置方向。

   const handleNext = () => {
     setDirection("right");
     setCurrentIndex((prevIndex) =>
       prevIndex + 1 === images.length ? 0 : prevIndex + 1
    );
  };
 ​
   const handlePrevious = () => {
     setDirection("left");
 ​
     setCurrentIndex((prevIndex) =>
       prevIndex - 1 < 0 ? images.length - 1 : prevIndex - 1
    );
  };
 ​
   const handleDotClick = (index) => {
     setDirection(index > currentIndex ? "right" : "left");
     setCurrentIndex(index);
  };

您可能已经注意到,我们不仅仅设置了handleNext和 的状态handlePrevious。我们也为handleDotClick. 因此,每当单击上一个或下一个点时,都会相应地设置方向。

只是提醒一下 - 方向的目的是设置图像的初始状态,以便滑块可以正常工作。

现在我们的方向已经确定,让我们在img元素中使用我们的变体。

 <AnimatePresence>
           <motion.img
             key={currentIndex}
             src={images[currentIndex]}
             variants={slideVariants}
             initial={direction === "right" ? "hiddenRight" : "hiddenLeft"}
             animate="visible"
             exit="exit"
           />
         </AnimatePresence>

所以我们添加variantsprop 并将其设置为等于slideVariants我们创建的。然后我们添加初始属性并将其设置为等于三元运算符。这会将图像的初始状态设置为 或 ,hiddenRight具体hiddenLeft取决于单击的slider_direction是 或dot。

接下来,我们添加 animate 属性,该属性将图像从初始位置动画到我们在属性中设置的位置visible。

最后,我们添加退出属性并将其设置为exit。当新图像进入时,这会将图像动画移出屏幕。

使用 Framer Motion 时可以使用许多道具。您可以查看文档以了解有关它们的更多信息。

完成后,我们的图像轮播应该可以完美运行。

 

滑块和点动画

我们可以到此为止,但我只想向我的幻灯片方向和点添加一些动画。

   const slidersVariants = {
     hover: {
       scale: 1.2,
       backgroundColor: "#ff00008e",
    },
  };
 const dotsVariants = {
     initial: {
       y: 0,
    },
     animate: {
       y: -10,
       scale: 1.3,
       transition: { type: "spring", stiffness: 1000, damping: "10" },
    },
     hover: {
       scale: 1.1,
       transition: { duration: 0.2 },
    },
  };

像往常一样,首先我们创建我们的变体。对于slidersVariants我们只需添加一个悬停属性。对于 ,dotsVariants我们有三个属性:initial、animate 和hover。

就像我们对img元素所做的那样,我们将添加motion.元素名称作为前缀,以便使用 Framer Motion。

 <div className="slide_direction">
   <motion.div
     variants={slidersVariants}
     whileHover="hover"
     className="left"
     onClick={handlePrevious}
   >
     <svg
       xmlns="/2000/svg"
       height="20"
       viewBox="0 96 960 960"
       width="20"
     >
       <path d="M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z" />
     </svg>
   </motion.div>
   <motion.div
     variants={slidersVariants}
     whileHover="hover"
     className="right"
     onClick={handleNext}
   >
     <svg
       xmlns="/2000/svg"
       height="20"
       viewBox="0 96 960 960"
       width="20"
     >
       <path d="m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z" />
     </svg>
   </motion.div>
 </div>;

如您所见,我们添加了变体并将其设置为等于slidersVariants。然后我们使用一个新属性whileHover并将其设置为等于我们在对象中指定的 over 属性slidersVariants。

 <motion.div
   key={index}
   className={`dot ${currentIndex === index ? "active" : ""}`}
   onClick={() => handleDotClick(index)}
   initial="initial"
   animate={currentIndex === index ? "animate" : ""}
   whileHover="hover"
   variants={dotsVariants}
 ></motion.div>;

这里我们不只是添加 whileHover 属性。我们还添加了一个initial道具和一个animate对当前图像点进行动画处理的道具,使其脱颖而出。

在我们的slidersVariants对象中,我们指定了弹簧的过渡类型,它在动画过渡发生时赋予其弹性性质。

将所有这些加在一起,我们时尚的图像轮播就准备好了。这是最终结果:

 

仅供参考,这是轮播组件的完整代码:

 import { useState } from "react";
 import { motion, AnimatePresence } from "framer-motion";
 ​
 const Carousel = ({ images }) => {
   const [currentIndex, setCurrentIndex] = useState(0);
   const [direction, setDirection] = useState(null);
 ​
   const slideVariants = {
     hiddenRight: {
       x: "100%",
       opacity: 0,
    },
     hiddenLeft: {
       x: "-100%",
       opacity: 0,
    },
     visible: {
       x: "0",
       opacity: 1,
       transition: {
         duration: 1,
      },
    },
     exit: {
       opacity: 0,
       scale: 0.8,
       transition: {
         duration: 0.5,
      },
    },
  };
   const slidersVariants = {
     hover: {
       scale: 1.2,
       backgroundColor: "#ff00008e",
    },
  };
   const dotsVariants = {
     initial: {
       y: 0,
    },
     animate: {
       y: -10,
       scale: 1.2,
       transition: { type: "spring", stiffness: 1000, damping: "10" },
    },
     hover: {
       scale: 1.1,
       transition: { duration: 0.2 },
    },
  };
 ​
   const handleNext = () => {
     setDirection("right");
     setCurrentIndex((prevIndex) =>
       prevIndex + 1 === images.length ? 0 : prevIndex + 1
    );
  };
 ​
   const handlePrevious = () => {
     setDirection("left");
 ​
     setCurrentIndex((prevIndex) =>
       prevIndex - 1 < 0 ? images.length - 1 : prevIndex - 1
    );
  };
 ​
   const handleDotClick = (index) => {
     setDirection(index > currentIndex ? "right" : "left");
     setCurrentIndex(index);
  };
 ​
   return (
     <div className="carousel">
         <div className="carousel-images">
         <AnimatePresence>
           <motion.img
             key={currentIndex}
             src={images[currentIndex]}
             initial={direction === "right" ? "hiddenRight" : "hiddenLeft"}
             animate="visible"
             exit="exit"
             variants={slideVariants}
           />
         </AnimatePresence>
         <div className="slide_direction">
           <motion.div
             variants={slidersVariants}
             whileHover="hover"
             className="left"
             onClick={handlePrevious}
           >
             <svg
               xmlns="/2000/svg"
               height="20"
               viewBox="0 96 960 960"
               width="20"
             >
               <path d="M400 976 0 576l400-400 56 57-343 343 343 343-56 57Z" />
             </svg>
           </motion.div>
           <motion.div
             variants={slidersVariants}
             whileHover="hover"
             className="right"
             onClick={handleNext}
           >
             <svg
               xmlns="/2000/svg"
               height="20"
               viewBox="0 96 960 960"
               width="20"
             >
               <path d="m304 974-56-57 343-343-343-343 56-57 400 400-400 400Z" />
             </svg>
           </motion.div>
         </div>
       </div>
       <div className="carousel-indicator">
        {images.map((_, index) => (
           <motion.div
             key={index}
             className={`dot ${currentIndex === index ? "active" : ""}`}
             onClick={() => handleDotClick(index)}
             initial="initial"
             animate={currentIndex === index ? "animate" : ""}
             whileHover="hover"
             variants={dotsVariants}
           ></motion.div>
        ))}
       </div>
     </div>
  );
 };
 export default Carousel;

查看GitHub上的 Git 存储库。

这是Netlify上的网站。

资源

我知道可能有些术语或语法不清楚,特别是如果您不熟悉 React 或不熟悉使用 Framer Motion。如果您想了解更多信息,我会推荐以下一些资源:

  • 反应文档

  • Framer 运动文档

  • 成帧运动课程

结论

在本文中,我们探索了使用 React 和 Framer Motion(动画和手势库)的强大组合来设计引人入胜且响应式图像轮播的过程。

通过合并诸如motion和 之类的组件AnimationPresence,我们能够穿过步骤来构建一个视觉上吸引人的旋转木马。该轮播展示了我们的图像,并通过迷人的动画提供图像之间的平滑过渡,以增强用户体验。

(更|多优质内|容:java567 点 c0m)

标签:React,const,轮播,动画,index,Motion,图像,我们
From: https://www.cnblogs.com/web-666/p/17524997.html

相关文章

  • React props 用法
    ComponentsletyousplittheUIintoindependent,reusablepieces,andthinkabouteachpieceinisolation.Thispageprovidesanintroductiontotheideaofcomponents.Youcanfinda detailedcomponentAPIreferencehere.Conceptually,componentsareli......
  • 7.3 轮播图图片路径报错的解决办法
    图片导入media文件夹后,启动前端打开主页界面,一直显示找不到图片的路径一直报/banner/banner.pngnotfound缺少media路径后来发现是dev配置文件中缺少了media的配置 需要填入如上图所示MEDIA_URL配置,之后只要用到media文件夹下的资源就会自动拼接media路径......
  • How to use handleChange() function in react component?
    An onChange eventistriggeredwhenvaluesareenteredintheinput.Thisfiresafunction handleChange(),thatisusedtosetanewstatefortheinput.1.HandlingSingleInputFirst,wehavetosetuptheinputfieldasacontrolledcomponentsothatw......
  • React hooks
    什么是ReactHook?hook(钩子)是一种特殊的函数,它允许你“钩入”各种React特性。假设一个函数返回一个有两个值的数组:第一个值: 一个带有状态state的变量。第二个值: 一个带有处理程序handle(改变当前状态的函数)的变量。就是这样,很简单。......
  • react之自定义hooks
    原文合集地址如下,有需要的朋友可以关注本文地址合集地址任何相对独立、复用性强的逻辑,都可以extract为自定义Hook,自定义Hook是一种复用React的状态逻辑的函数。自定义Hook的主要特点是:抽象组件间的状态逻辑,方便复用让功能组件更纯粹,更易于维护自定义Hook可......
  • react-native项目启动报错 Error: `fsevents` unavailable (this watcher can only be
    react-native项目启动报错——watchman安装问题(macpro) LookingforJSfilesin/Users/你的名称/Documents/project/文件夹名Loadingdependencygraph.../Users/你的名称/Documents/project/文件夹名/node_modules/metro/node_modules/sane/src/fsevents_watcher.js:37......
  • react项目webpack打包图片名去除hash
    环境:node-vv16.16.01、露出webpack配置文件:yarnruneject如果git报错,请执行gitadd.gitcommit-m'ddd'再执行yarnruneject2、执行完上一步后,项目会新增一个config文件夹 修改config\webpack.config.js 修改图片:搜索media,一般在218行出现:“assetModule......
  • React - 14 Hooks组件之useRef
    1.获取元素的3种方式方式1:ref={x=>refName=x}函数组件中没有this,直接给了一个变量。(可以用但是不推荐)方式2React.createRef()方式3useRef(null)2.函数组件用useRef,类组件用React.createRefimportReact,{useState,useEffect,useRef}from"react";import{Butto......
  • React - 13 Hooks组件之useEffect
    1.useEffectimportReact,{useState,useEffect}from"react";import{Button}from'antd';import'./Demo.less';/*useEffect:在函数组件中,使用生命周期函数useEffect(callback):没设置依赖+第一次渲染完毕后,执行callback,等价于componentDidMount......
  • Environment Perception and Motion Strategy for Transformable Legged Wheel Robot
    论文发表于2018年。这篇论文介绍了三模式机器人在野外环境下的环境感知和模式切换策略。机器人拥有arcmode、roundmode、clawmode三种模式。图a表示由roundmode变换至arcmode,图b表示由arcmode变换为clawmode。 1.感知1.1 周围环境感知。分为环境建模和障碍物感......