如何使用React和Framer Motion構(gòu)建圖像輪播
輪播可以幫助您節(jié)省空間、增強(qiáng)用戶界面并提供出色的用戶體驗。
輪播已成為 UI 設(shè)計的主要內(nèi)容,通常用于顯示圖像、推薦等。創(chuàng)建引人入勝的動態(tài)界面時,它們是不可或缺的。
(更|多優(yōu)質(zhì)內(nèi)|容:java567 點(diǎn) c0m)
什么是成幀器運(yùn)動?
這是一個用于 React 應(yīng)用程序的開源動畫庫,您可以使用它為我們的 Web 應(yīng)用程序創(chuàng)建動態(tài)和響應(yīng)式動畫。
Framer Motion 有幾個有用的功能,包括:
動畫:這允許您為組件進(jìn)行無縫過渡。
手勢:它支持觸摸和鼠標(biāo)動作,允許您考慮某些事件。
變體:Framer Motion 使您能夠以聲明方式聲明組件,從而保持代碼的組織性和可重用性。
所有這些功能都非常有用,我們很快就會看到它們的實際應(yīng)用。
要更深入地了解 Framer Motion,您可以瀏覽其文檔和資源。但在本文中,我們將重點(diǎn)關(guān)注基礎(chǔ)知識。當(dāng)我指導(dǎo)您了解使用 Framer Motion 的基礎(chǔ)知識時,我的主要目標(biāo)是構(gòu)建令人印象深刻且引人入勝的圖像輪播。
如何設(shè)置您的開發(fā)環(huán)境
我們要做的第一件事是設(shè)置您的開發(fā)環(huán)境。這涉及安裝必要的包以成功構(gòu)建您的應(yīng)用程序。這包括安裝Node.js和npm
如果您已經(jīng)安裝了 Node.js 和 npm,則無需再次下載并安裝它們。
創(chuàng)建一個 React 應(yīng)用程序
此時,我假設(shè)您已經(jīng)安裝了 Node 和 npm。要創(chuàng)建 React 應(yīng)用程序,只需轉(zhuǎn)到終端并訪問您希望應(yīng)用程序所在的目錄。然后運(yùn)行以下命令:
?npx create-react-app react-image-carousel
您可以為您的應(yīng)用程序命名任何您想要的名稱 - 但出于本文的目的,我將其命名為react-image-carousel.
成功創(chuàng)建 React 應(yīng)用程序后,在代碼編輯器中打開您的目錄。您應(yīng)該獲得一些默認(rèn)文件和樣式,它應(yīng)該如下所示:
我們不需要此項目中的大部分文件和樣式,因此您可以清理以下文件:app.test.js、logo.svg、reportWebVitals.js、setupTest.js。您還可以刪除 App.css 表中的所有默認(rèn)樣式。
現(xiàn)在您的 React 應(yīng)用程序已創(chuàng)建并設(shè)置完畢,為此項目設(shè)置開發(fā)環(huán)境的最后一步是安裝 Framer Motion。
為此,只需轉(zhuǎn)到終端確保您位于項目目錄中并運(yùn)行以下命令:
? npm ?install framer-motion
這應(yīng)該安裝最新版本的 Framer Motion?,F(xiàn)在你應(yīng)該可以走了。只需用于npm run start在瀏覽器上啟動開發(fā)服務(wù)器即可。
如何設(shè)計圖像輪播組件
為了開始設(shè)計,我們首先創(chuàng)建一個Carousel.js組件。在輪播組件中,我們將從useStateReact 導(dǎo)入鉤子,然后從 Framer Motion導(dǎo)入motion和屬性。AnimatePresence
?import { useState } from "react";
?import { motion, AnimatePresence } from "framer-motion";
然后我們創(chuàng)建 carousel 函數(shù),該函數(shù)接受imagesprop,該 prop 是圖像 URL 的數(shù)組:
?const Carousel = ({ images }) => {};
在我們的 carousel 函數(shù)中,我們使用 useState 初始化一個狀態(tài)變量,以跟蹤我們用作setCurrentIndex更新索引的相應(yīng)函數(shù)的當(dāng)前圖像索引。
接下來,我們創(chuàng)建 3 個輔助函數(shù)來處理用戶交互,其中包括:
handleNext:這會將 currentIndex 更新為下一個索引,以便更改圖像,如果到達(dá)數(shù)組末尾,則循環(huán)返回。
handlePrevious:這與handleNext 函數(shù)的作用相同,但這次順序相反。這使我們能夠回到圖像。
handleDotClick:這將索引作為參數(shù)并更新 currentIndex。這樣,我們只需單擊這些點(diǎn)就可以向前和向后跳轉(zhuǎn)到圖像。
?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);
? ?};
這些是我們的組件所需的輔助函數(shù)
如何創(chuàng)建我們的模板
我們的模板非常簡單,由圖像、滑塊方向和點(diǎn)(指示器)組成。
? ?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>
? ?);
正如您在模板中看到的,我們在當(dāng)前索引處顯示圖像。然后我們有一個 div,其中包含兩個帶有類名和 的slider_directiondiv 。我們將它們創(chuàng)建為輪播的導(dǎo)航按鈕。它們使用內(nèi)聯(lián) SVG 來顯示箭頭圖標(biāo),并且它們的 onClick 處理程序分別設(shè)置為和。leftrighthandlePrevious``handleNext
我們還有一個指示器 div,我們創(chuàng)建它來顯示代表輪播中每個圖像的一系列點(diǎn)。它映射圖像數(shù)組并為每個圖像創(chuàng)建一個點(diǎn),為與currentIndex.
然后,我們?yōu)槊總€點(diǎn)附加一個 onClick 處理程序,該處理程序設(shè)置handleDotClick為使用點(diǎn)的索引進(jìn)行調(diào)用。
現(xiàn)在這應(yīng)該是我們的模板。剩下的就是導(dǎo)出 carousel 組件,將其導(dǎo)入到App.js組件中,并添加一些 CSS。然后我們就準(zhǔn)備開始制作動畫了。
因此,我們只需從組件中導(dǎo)出輪播功能即可Carousel.js。
?export default Carousel;
如何使用輪播組件
我們已經(jīng)創(chuàng)建了輪播組件。但要使用它,我們必須將其導(dǎo)入到我們的 App.js 組件中:
?import Carousel from "./Carousel";
之后,我們可以創(chuàng)建圖像數(shù)組,它將保存我們的圖像 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 函數(shù),它將保存我們的應(yīng)用程序模板。
?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;
正如您所看到的,我們的標(biāo)題僅顯示一個標(biāo)題,顯示我們的應(yīng)用程序的內(nèi)容。
然后我們有主要部分,其中添加了輪播組件并接受圖像數(shù)組的道具。如果您還記得,這是我們在輪播組件中用于顯示圖像的道具。
最后,我們導(dǎo)出 App 組件,以便我們可以在 index.js 文件中使用它。
要在沒有樣式的情況下查看所有這些,請運(yùn)行命令npm run start。該應(yīng)用程序應(yīng)如下所示:
丑陋吧?是的,我同意你的看法。但只需幾行 CSS,這一切就會發(fā)生轉(zhuǎn)變。那么讓我們深入了解一下吧。
如何添加 CSS
我不想為輪播組件創(chuàng)建單獨(dú)的樣式表,因此我們將在 App.css 文件中完成所有 CSS 操作。不要忘記導(dǎo)入樣式表。
?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 的結(jié)果:
您可能會同意,這看起來好多了,而且功能已經(jīng)齊全。
現(xiàn)在讓我們繼續(xù)使用 Framer Motion 添加動畫,使其具有漂亮的滑動外觀。
如何向輪播組件添加動畫
要開始使用 Framer Motion 制作動畫,您必須熟悉一些概念,因為我們將在本節(jié)中經(jīng)常使用它們。這些概念包括:
變體:將變體視為一組命名的屬性。它的工作是定義元素應(yīng)該如何顯示或動畫。您可以創(chuàng)建不同的變體來表示元素的不同視覺狀態(tài)或動畫,例如open、closed、hover等。
初始狀態(tài):這就是動畫開始之前對象所具有的狀態(tài)。
動畫:這只是你的對象將要動畫的狀態(tài),就這么簡單。
回到項目,我們將動畫添加到輪播組件中。我們已經(jīng)導(dǎo)入了我們需要的兩個屬性 -motion和AnimatePresence屬性。
我將把本節(jié)分為三個部分,因為我們將向代碼的三個部分添加動畫,包括圖像、滑塊方向和指示點(diǎn)。
圖像動畫
為了對圖像的退出和進(jìn)入進(jìn)行動畫處理,我們需要用一個 組件來包裝我們的img元素。AnimationPresence這使我們能夠在圖像離開或進(jìn)入時添加動畫。然后我們motion.像這樣將 a 附加到我們的標(biāo)簽上。
? <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:這會將圖像的不透明度設(shè)置為 0 并將其放置在容器的右側(cè)。
hiddenLeft:這與hiddenRight 的作用相同,但這次它設(shè)置在左側(cè)。
可見:無論圖像位于容器中心的哪個位置,都會調(diào)用此屬性來實現(xiàn)幻燈片動畫。
exit:此動畫控制當(dāng)另一個圖像滑入時從屏幕上刪除圖像。
現(xiàn)在我們的變體已經(jīng)設(shè)置好了。我們?nèi)绾沃缊D像應(yīng)該從哪里滑入?我們需要設(shè)置一個方向狀態(tài)并根據(jù)slide_direction單擊的 s 來更新狀態(tài)。
? ?const [direction, setDirection] = useState('left');
所以我們將方向設(shè)置為從左側(cè)開始。這只是合乎邏輯的,因為要顯示的第一幅圖像將是第一幅圖像。然后我們轉(zhuǎn)到輔助函數(shù)并根據(jù)單擊的方向設(shè)置方向。
? ?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);
? ?};
您可能已經(jīng)注意到,我們不僅僅設(shè)置了handleNext和 的狀態(tài)handlePrevious。我們也為handleDotClick. 因此,每當(dāng)單擊上一個或下一個點(diǎn)時,都會相應(yīng)地設(shè)置方向。
只是提醒一下 - 方向的目的是設(shè)置圖像的初始狀態(tài),以便滑塊可以正常工作。
現(xiàn)在我們的方向已經(jīng)確定,讓我們在img元素中使用我們的變體。
?<AnimatePresence>
? ? ? ? ? ?<motion.img
? ? ? ? ? ? ?key={currentIndex}
? ? ? ? ? ? ?src={images[currentIndex]}
? ? ? ? ? ? ?variants={slideVariants}
? ? ? ? ? ? ?initial={direction === "right" ? "hiddenRight" : "hiddenLeft"}
? ? ? ? ? ? ?animate="visible"
? ? ? ? ? ? ?exit="exit"
? ? ? ? ? ?/>
? ? ? ? ?</AnimatePresence>
所以我們添加variantsprop 并將其設(shè)置為等于slideVariants我們創(chuàng)建的。然后我們添加初始屬性并將其設(shè)置為等于三元運(yùn)算符。這會將圖像的初始狀態(tài)設(shè)置為 或 ,hiddenRight具體hiddenLeft取決于單擊的slider_direction是 或dot。
接下來,我們添加 animate 屬性,該屬性將圖像從初始位置動畫到我們在屬性中設(shè)置的位置visible。
最后,我們添加退出屬性并將其設(shè)置為exit。當(dāng)新圖像進(jìn)入時,這會將圖像動畫移出屏幕。
使用 Framer Motion 時可以使用許多道具。您可以查看文檔以了解有關(guān)它們的更多信息。
完成后,我們的圖像輪播應(yīng)該可以完美運(yùn)行。
滑塊和點(diǎn)動畫
我們可以到此為止,但我只想向我的幻燈片方向和點(diǎn)添加一些動畫。
? ?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 },
? ? ?},
? ?};
像往常一樣,首先我們創(chuàng)建我們的變體。對于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>;
如您所見,我們添加了變體并將其設(shè)置為等于slidersVariants。然后我們使用一個新屬性whileHover并將其設(shè)置為等于我們在對象中指定的 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對當(dāng)前圖像點(diǎn)進(jìn)行動畫處理的道具,使其脫穎而出。
在我們的slidersVariants對象中,我們指定了彈簧的過渡類型,它在動畫過渡發(fā)生時賦予其彈性性質(zhì)。
將所有這些加在一起,我們時尚的圖像輪播就準(zhǔn)備好了。這是最終結(jié)果:
僅供參考,這是輪播組件的完整代碼:
?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上的網(wǎng)站。
資源
我知道可能有些術(shù)語或語法不清楚,特別是如果您不熟悉 React 或不熟悉使用 Framer Motion。如果您想了解更多信息,我會推薦以下一些資源:
反應(yīng)文檔
Framer 運(yùn)動文檔
成幀運(yùn)動課程
結(jié)論
在本文中,我們探索了使用 React 和 Framer Motion(動畫和手勢庫)的強(qiáng)大組合來設(shè)計引人入勝且響應(yīng)式圖像輪播的過程。
通過合并諸如motion和 之類的組件AnimationPresence,我們能夠穿過步驟來構(gòu)建一個視覺上吸引人的旋轉(zhuǎn)木馬。該輪播展示了我們的圖像,并通過迷人的動畫提供圖像之間的平滑過渡,以增強(qiáng)用戶體驗。