📅  最后修改于: 2023-12-03 14:52:01.770000             🧑  作者: Mango
在本文中,我们将学习如何使用 React 和 framer-motion 库来创建 Tinder-式的刷卡手势动画效果。在本教程的最终部分,我们会获得一个完整的基于 React 和 framer-motion 库的 Tinder 应用程序。
在开始之前,确保你拥有最新版本的 Node.js 和 npm。你可以使用以下命令检查它们的版本:
node -v
npm -v
然后创建一个新的 React 应用程序:
npx create-react-app my-tinder-app
cd my-tinder-app
安装 framer-motion 库:
npm install framer-motion
现在,我们已经准备好开始构建我们的应用程序。
我们要构建一个卡片堆栈,它可以通过手势向左或向右滑动每个卡片。每个卡片都应该能够反弹并返回到屏幕中心。为了实现这个效果,我们将使用 framer-motion 库中的 motion
组件。
在 src
文件夹下创建一个名为 CardStack
的新组件,并在其中添加以下代码:
import React from "react";
import { motion } from "framer-motion";
const cardStyle = {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 10,
backgroundColor: "white",
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.1)",
padding: "20px",
};
const CardStack = () => {
return (
<div style={{ position: "relative", height: "500px" }}>
<motion.div
style={cardStyle}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
whileDrag={{ scale: 0.98 }}
/>
</div>
);
};
export default CardStack;
现在,我们有了一个简单的卡片堆栈,其中包含一个可以水平拖动的卡片。这里我们设置了限制,使卡片不能在屏幕外拖动,并且在拖动时卡片会稍微缩小一点。
现在我们需要一些数据来渲染到我们的卡片堆栈中。在 src
文件夹下创建一个名为 data.js
的新文件,并添加一些示例数据:
export const users = [
{
id: 1,
name: "Samantha",
age: 23,
bio: "Hi, I'm Samantha and I love hiking and photography.",
image: "https://i.pravatar.cc/300?img=1",
},
{
id: 2,
name: "Alex",
age: 27,
bio: "Hey, I'm Alex and I'm a foodie and a gamer.",
image: "https://i.pravatar.cc/300?img=2",
},
{
id: 3,
name: "Emily",
age: 25,
bio: "Hi there, I'm Emily and I'm an artist and a musician.",
image: "https://i.pravatar.cc/300?img=3",
},
{
id: 4,
name: "Michael",
age: 30,
bio: "Hey, I'm Michael and I'm a traveler and an adventure seeker.",
image: "https://i.pravatar.cc/300?img=4",
},
];
这里我们定义了每个用户的 id
、name
、age
、bio
和 image
。现在,我们已经准备好将这些数据渲染到我们的卡片堆栈中。
我们将使用 CardStack
组件来渲染我们的卡片堆栈。首先,我们需要在组件中导入要使用的数据和组件:
import React from "react";
import { motion } from "framer-motion";
import { users } from "./data";
import Card from "./Card";
然后,我们需要将所有用户数据 mapping 到卡片组件中:
const CardStack = () => {
return (
<div style={{ position: "relative", height: "500px" }}>
{users.map((user) => (
<Card key={user.id} user={user} />
))}
</div>
);
};
现在我们需要为每个用户创建一个卡片组件。在 src
文件夹下创建一个名为 Card
的新组件,并添加以下代码:
import React from "react";
import { motion } from "framer-motion";
const cardStyle = {
position: "absolute",
top: 0,
left: 0,
right: 0,
bottom: 0,
borderRadius: 10,
backgroundColor: "white",
boxShadow: "0px 4px 20px rgba(0, 0, 0, 0.1)",
padding: "20px",
};
const Card = ({ user }) => {
return (
<motion.div
style={cardStyle}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
whileDrag={{ scale: 0.98 }}
>
<img src={user.image} alt={user.name} />
<h1>{user.name}, {user.age}</h1>
<p>{user.bio}</p>
</motion.div>
);
};
export default Card;
我们在卡片组件中渲染了每个用户的姓名、年龄、个人简介和头像。现在我们可以看到所有卡片被成功渲染到屏幕上。
现在我们将添加滑动手势来移动卡片。我们将使用 useMotionValue
和 useTransform
钩子来指定某个值与手势交互时该如何变化。我们还将使用 useSpring
和 useTransform
钩子来为在拖动结束时添加反弹效果。
在 Card
组件中,我们将添加以下代码:
import { useMotionValue, useTransform, useSpring } from "framer-motion";
const Card = ({ user }) => {
const x = useMotionValue(0);
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);
const rotate = useTransform(x, [-200, 0, 200], [-45, 0, 45]);
const imageOpacity = useTransform(x, [-200, 0, 200], [0, 1, 0.2]);
const scale = useSpring(useTransform(opacity, [0, 1], [1, 1.1]));
return (
<motion.div
style={{
...cardStyle,
opacity,
x,
rotate,
}}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
whileDrag={{ scale: 0.98 }}
onDragEnd={(event, info) => {
const swipe = Math.round(info.offset.x / 200);
const swipeDirection = swipe === 0 ? 0 : swipe > 0 ? 1 : -1;
console.log(`Swiped ${swipeDirection}`);
}}
>
<img src={user.image} alt={user.name} style={{ opacity: imageOpacity, scale }} />
<h1>{user.name}, {user.age}</h1>
<p>{user.bio}</p>
</motion.div>
);
};
在以上代码中,我们钩入了卡片的 x
、opacity
和 rotate
旋转变换,当我们使用手势滑动卡片时,这些值将相应地更新。我们还为图像添加了不同的 opacity
和 scale
变换,并使用 useSpring
钩子为止在卡片拖动结束时添加了反弹效果。
注意: 我们还通过 onDragEnd
回调捕获了滑动卡片后的位置信息,并通过调用 Math.round(info.offset.x / 200)
计算出滑动方向。这里我们使用 200
作为阈值,如果滑动位置大于 200
,则认为是向右滑动,否则认为向左滑动。
现在我们需要在卡片上添加喜欢或不喜欢的图标,以便用户可以指定他们的选择。我们将使用 FontAwesome 图标库中的图标。
在 Card
组件中添加以下代码:
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faTimes, faHeart } from "@fortawesome/free-solid-svg-icons";
const Card = ({ user }) => {
const x = useMotionValue(0);
const opacity = useTransform(x, [-200, 0, 200], [0, 1, 0]);
const rotate = useTransform(x, [-200, 0, 200], [-45, 0, 45]);
const imageOpacity = useTransform(x, [-200, 0, 200], [0, 1, 0.2]);
const scale = useSpring(useTransform(opacity, [0, 1], [1, 1.1]));
return (
<motion.div
style={{
...cardStyle,
opacity,
x,
rotate,
}}
drag="x"
dragConstraints={{ left: 0, right: 0 }}
whileDrag={{ scale: 0.98 }}
onDragEnd={(event, info) => {
const swipe = Math.round(info.offset.x / 200);
const swipeDirection = swipe === 0 ? 0 : swipe > 0 ? 1 : -1;
console.log(`Swiped ${swipeDirection}`);
}}
>
<img src={user.image} alt={user.name} style={{ opacity: imageOpacity, scale }} />
<h1>{user.name}, {user.age}</h1>
<p>{user.bio}</p>
<div style={{ position: "absolute", bottom: "20px", left: "20px" }}>
<FontAwesomeIcon icon={faTimes} size="2x" color="red" />
</div>
<div style={{ position: "absolute", bottom: "20px", right: "20px" }}>
<FontAwesomeIcon icon={faHeart} size="2x" color="green" />
</div>
</motion.div>
);
};
这段代码添加了两个图标: faTimes
和 faHeart
。我们将这些图标添加到卡片的顶部和底部,并将红色和绿色作为其颜色。现在,我们已经成功地实现了卡片的喜欢和不喜欢功能。
最后一步是将所有卡片堆放在一起,并使其看起来像是一个卡片堆栈。我们要做的是将每个卡片向上移动,留出较小的部分,并对最后一个卡片进行一些不同的变换。
在 CardStack
组件中添加以下代码:
const CardStack = () => {
const stackStyle = {
position: "relative",
height: "500px",
padding: "20px 0",
};
const lastCardStyle = {
...cardStyle,
position: "absolute",
top: "0",
left: "0",
right: "0",
bottom: "0",
margin: "auto",
};
return (
<div style={stackStyle}>
{users.slice(0, 3).map((user, index) => (
<Card key={user.id} user={user} style={{ zIndex: users.length - index }} />
))}
<motion.div style={lastCardStyle} animate={{ scale: 0.9, rotate: 5 }} />
</div>
);
};
在以上代码中,我们将卡片数组裁剪为前三个卡片,并将它们向上移动,留下一个较小的部分。我们使用 zIndex
属性定义了每个卡片的层次结构,使其看起来像是一个堆栈。
我们还添加了一个最后一个卡片,它使用 animate
变换缩放和旋转。现在我们已经成功地构建了一个基于 React 和 framer-motion 库的 Tinder 应用程序。
恭喜!你已经学会了如何使用 React 和 framer-motion 库来创建类似 Tinder 的刷卡手势效果。在本教程中,我们学习了如何构建一个卡片堆栈,并呈现用户数据。我们还学习了如何使用手势和反弹效果来移动卡片,并添加了喜欢和不喜欢的功能。最后,我们添加了一个卡片堆叠布局来使它看起来更像是一个真正的 Tinder 应用程序。
完整代码及运行效果请参见:https://codesandbox.io/s/react-framer-motion-tinder-98iol