如何使用 React 和 framer-motion 创建 Tinder 刷卡手势?
我们可以使用 ReactJS 中的Framer模块使用以下方法创建一个简单的 tinder 应用程序,例如滑动手势。
先决条件:
- JavaScript(ES6)知识
- 熟悉 HTML/CSS。
- ReactJS 的基础知识。
用于构建此应用程序的 Framer 挂钩是:
- 成帧器使用MotionValue
- 成帧器使用变换
- Framer 使用动画
创建 React 应用程序并安装模块:
第 1 步:使用以下命令创建一个 React 应用程序。
npx create-react-app tinder-swipe
第 2 步:创建项目文件夹(即tinder-swipe)后,使用以下命令移动到该文件夹。
cd tinder-swipe
第 3 步:创建 ReactJS 应用程序后,使用以下命令安装成帧器模块。
npm install framer
项目结构:我们的项目结构树应该是这样的:
方法:
- 我们将使用useMotionValue()在用户拖动光标时移动卡片,因为所有运动组件内部都使用 motionValues 来跟踪我们将通过这个钩子获得的动画值的状态和速度。
- 我们将使用useTransform()钩子来旋转卡片,因为卡片在拖动时通过链接卡片的motionValue来移动。
- 此外,我们将使用useTransform()挂钩通过将卡片链接到 motionValue 来更改卡片移动时的不透明度。
- useAnimation()是一个实用程序挂钩,用于创建动画控件 (animControls),可用于手动启动、停止和序列化卡片上的动画。
示例 1:
index.js
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import { Frame, useMotionValue, useTransform, useAnimation } from "framer";
// Some styling for the card
const style = {
backgroundImage: "URL(
https://img.icons8.com/color/452/GeeksforGeeks.png)",
backgroundRepeat: "no-repeat",
backgroundSize: "contain",
backgroundColor: "#55ccff",
boxShadow: "5px 10px 18px #888888",
borderRadius: 10,
height: 300,
};
const App = () => {
// To move the card as the user drags the cursor
const motionValue = useMotionValue(0);
// To rotate the card as the card moves on drag
const rotateValue = useTransform(motionValue, [-200, 200], [-50, 50]);
// To decrease opacity of the card when swiped
// on dragging card to left(-200) or right(200)
// opacity gradually changes to 0
// and when the card is in center opacity = 1
const opacityValue = useTransform(
motionValue,
[-200, -150, 0, 150, 200],
[0, 1, 1, 1, 0]
);
// Framer animation hook
const animControls = useAnimation();
return (
{
// If the card is dragged only upto 150 on x-axis
// bring it back to initial position
if (Math.abs(info.point.x) <= 150) {
animControls.start({ x: 0 });
} else {
// If card is dragged beyond 150
// make it disappear
// making use of ternary operator
animControls.start({ x: info.point.x < 0 ? -200 : 200 });
}
}}
/>
);
};
ReactDOM.render( , document.getElementById("root"));
index.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.App {
text-align: center;
}
code {
font-family: source-code-pro, Menlo,
Monaco, Consolas, 'Courier New',
monospace;
}
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Frame, useMotionValue, useTransform, useAnimation } from 'framer';
// Card component with destructured props
const Card = ({ image, color }) => {
// To move the card as the user drags the cursor
const motionValue = useMotionValue(0);
// To rotate the card as the card moves on drag
const rotateValue = useTransform(motionValue, [-200, 200], [-50, 50]);
// To decrease opacity of the card when swiped
// on dragging card to left(-200) or right(200)
// opacity gradually changes to 0
// and when the card is in center opacity = 1
const opacityValue = useTransform(
motionValue,
[-200, -150, 0, 150, 200],
[0, 1, 1, 1, 0]
);
// Framer animation hook
const animControls = useAnimation();
// Some styling for the card
// it is placed inside the card component
// to make backgroundImage and backgroundColor dynamic
const style = {
backgroundImage: `url(${image})`,
backgroundRepeat: 'no-repeat',
backgroundSize: 'contain',
backgroundColor: color,
boxShadow: '5px 10px 18px #888888',
borderRadius: 10,
height: 300
};
return (
{
// If the card is dragged only upto 150 on x-axis
// bring it back to initial position
if (Math.abs(info.point.x) <= 150) {
animControls.start({ x: 0 });
} else {
// If card is dragged beyond 150
// make it disappear
// Making use of ternary operator
animControls.start({ x: info.point.x < 0 ? -200 : 200 });
}
}}
/>
);
};
const App = () => {
const cards = [
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#55ccff'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#e8e8e8'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#0a043c'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: 'black'
}
];
return (
{/* Traversing through cards arrray using map function
and populating card with different image and color */}
{cards.map((card) => (
))}
);
};
ReactDOM.render( , document.getElementById('root'));
索引.css
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont,
'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans',
'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.App {
text-align: center;
}
code {
font-family: source-code-pro, Menlo,
Monaco, Consolas, 'Courier New',
monospace;
}
运行应用程序的步骤:使用以下命令从项目的根目录运行应用程序。
npm start
输出:现在打开浏览器并转到http://localhost:3000/ ,您将看到以下输出:
示例 2:创建一副牌
index.js
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { Frame, useMotionValue, useTransform, useAnimation } from 'framer';
// Card component with destructured props
const Card = ({ image, color }) => {
// To move the card as the user drags the cursor
const motionValue = useMotionValue(0);
// To rotate the card as the card moves on drag
const rotateValue = useTransform(motionValue, [-200, 200], [-50, 50]);
// To decrease opacity of the card when swiped
// on dragging card to left(-200) or right(200)
// opacity gradually changes to 0
// and when the card is in center opacity = 1
const opacityValue = useTransform(
motionValue,
[-200, -150, 0, 150, 200],
[0, 1, 1, 1, 0]
);
// Framer animation hook
const animControls = useAnimation();
// Some styling for the card
// it is placed inside the card component
// to make backgroundImage and backgroundColor dynamic
const style = {
backgroundImage: `url(${image})`,
backgroundRepeat: 'no-repeat',
backgroundSize: 'contain',
backgroundColor: color,
boxShadow: '5px 10px 18px #888888',
borderRadius: 10,
height: 300
};
return (
{
// If the card is dragged only upto 150 on x-axis
// bring it back to initial position
if (Math.abs(info.point.x) <= 150) {
animControls.start({ x: 0 });
} else {
// If card is dragged beyond 150
// make it disappear
// Making use of ternary operator
animControls.start({ x: info.point.x < 0 ? -200 : 200 });
}
}}
/>
);
};
const App = () => {
const cards = [
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#55ccff'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#e8e8e8'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: '#0a043c'
},
{
image: 'https://img.icons8.com/color/452/GeeksforGeeks.png',
color: 'black'
}
];
return (
{/* Traversing through cards arrray using map function
and populating card with different image and color */}
{cards.map((card) => (
))}
);
};
ReactDOM.render( , document.getElementById('root'));
运行应用程序的步骤:从项目的根目录使用以下命令运行应用程序:
npm start
输出:现在打开浏览器并转到http://localhost:3000/ ,您将看到以下输出: