当前位置: 首页 > news >正文

Motion动画的几个例子

用useInView触发动画

用useAnimation控制动画

其中 whileTap="tapsss"也表明key的值可以自定义,whileTap也可以接函数

import { motion, useAnimation } from "framer-motion";
import { useEffect, useRef } from "react";
import { useInView } from "framer-motion"; // 一个辅助判断元素是否在视口中的钩子// 示例:当元素滚动进入视口时开始动画
export default () => {const controls = useAnimation();const ref = useRef(null);const isInView = useInView(ref); // 判断元素是否在视口内useEffect(() => {// 当元素进入视口时,启动动画if (isInView) {controls.start("visible");}}, [isInView]);const elementVariants = {hidden: { opacity: 0, y: 50 },visible: {opacity: 1,y: 0,transition: { delay: 1, duration: 0.6, ease: "easeOut" }},tapsss: {scale: 0.5}};return (<motion.divref={ref}variants={elementVariants}initial="hidden"whileTap="tapsss"animate={controls} // 使用 controls 控制动画style={{ width: 200, height: 200, backgroundColor: "green" }}>当我进入视野时,动画开始</motion.div>);
};

触发动画的方式之点击按钮

import { motion } from "framer-motion";
import { useState } from "react";// 示例:点击按钮开始动画
export default () => {const [isAnimating, setIsAnimating] = useState(false);// 定义动画变体(Variants)const boxVariants = {initial: { opacity: 0, scale: 0.5 },animate: { opacity: 1, scale: 1, transition: { duration: 0.5 } }};return (<div>{/* 通过点击事件控制动画 */}<motion.buttononClick={() => setIsAnimating(true)}>开始动画</motion.button><motion.divvariants={boxVariants}initial="initial" // 初始状态animate={isAnimating ? "animate" : "initial"} // 根据状态决定动画style={{ width: 100, height: 100, backgroundColor: "#38f" }}/></div>);
};

完整播放点击动画之一(点击别的元素触发动画)

用来做移动端按钮的点击效果不错

import { motion, useAnimation } from "framer-motion";
import { useState } from "react";
export default () => {const controls = useAnimation();const [isPlaying, setIsPlaying] = useState(false);// 手动触发一系列动画const startSequence = async () => {setIsPlaying(true);await controls.start({x: 100,backgroundColor: "#f00",transition: { duration: 0.5 }});await controls.start({y: 100,backgroundColor: "#0f0",transition: { duration: 0.5 }});await controls.start({x: 0,y: 0,backgroundColor: "#00f",transition: {duration: 0.5,ease: "backOut" // 添加一点弹性效果}});setIsPlaying(false);};return (<div><button onClick={startSequence} disabled={isPlaying}>{isPlaying ? "动画播放中..." : "开始序列动画"}</button><motion.divanimate={controls} // 手动控制的动画状态style={{width: 100,height: 100,backgroundColor: "blue",marginTop: 20}}/></div>);
};

完整播放点击动画之二(点击自身触发动画)

核心都是利用  const controls = useAnimation();控制动画

都是执行一个函数,里面用 controls.start开启动画

 controls.start的实参不仅可以是对象,也可以是字符串(比如本文的例子"用useInView触发动画")

import { motion, useAnimation } from "framer-motion";
//点击按钮触发动画
//模拟whileTap,使点击按钮后,可以完整播放动画,而不是只播放一半
//重点是点击后,完整播放完动画
export default () => {const controls = useAnimation();const handleTap = async () => {// 在这里执行任意逻辑await controls.start({scale: 0.8,rotate: 30,transition: { duration: 0.2 }});await controls.start({scale: 1,rotate: 0,transition: { duration: 0.2, ease: 'backOut' }});};return (<motion.buttonanimate={controls}onTapStart={handleTap}style={{ padding: 20, background: "#666", color: "white" }}>点我(函数控制)</motion.button>);
};

父子动画

细节:非直接子元素也是可以有动画效果

细节2: ​​子元素继承父级的动画状态​

子元素只有一个属性 <motion.div variants={itemVariants}>

  • 虽然没有显式写 animate或 initial,但它会​​隐式继承父级当前的状态名​​(即 "visible"或 "hidden")。

  • 父级的状态名(如 "visible")会直接传递给子元素,子元素通过匹配 itemVariants中的同名状态(visible或 hidden)来执行动画。

import { motion } from "framer-motion";
import { useState } from "react";// 示例:点击按钮开始动画
export default () => {const [isAnimating, setIsAnimating] = useState(false);const containerVariants = {hidden: { opacity: 0 },visible: {opacity: 1,transition: {// 父元素动画开始后,延迟1.2秒再开始子元素动画delayChildren: 1.2,// 每个子元素依次出现,间隔0.5秒staggerChildren: 0.5}}};const itemVariants = {hidden: { opacity: 0, x: -50 },visible: {opacity: 1, x: 0, transition: {duration: 0.5,ease: "backOut"}}};return (<div><button onClick={() => { setIsAnimating(!isAnimating) }}>按钮</button><motion.divinitial="hidden"animate={isAnimating ? "visible" : "hidden"}variants={containerVariants}style={{width: 300,height: 300,color: '#fff',backgroundColor: "blue",marginTop: 20}}><div><section><motion.div variants={itemVariants}>11111111111</motion.div><motion.div variants={itemVariants}>22222222222</motion.div><motion.div variants={itemVariants}>33333333333</motion.div><motion.div variants={itemVariants}>44444444444</motion.div></section></div></motion.div></div>);
};

whileInView一些API

import { motion } from "framer-motion";const buttonVariants = {yiGeMinZi: {y: [100, 0, 50], // 自定义关键帧backgroundColor: ['#f00', '#38f', '#ac1'],transition: {delay: 1,duration: 2,times: [0, 0.7, 1],   // 70%时间用于0.8→1.2ease: "easeInOut"}}
};export default function HoverButton() {return (<motion.buttonvariants={buttonVariants}whileInView="yiGeMinZi"viewport={{ amount: 0.3, once: true }} // 30% 进入视口时触发,只触发一次initial={{ scale: 0.8 }}style={{ padding: "10px 20px" }}>悬停我</motion.button>);
}

利用whileInView的错开动画

viewport={{ once: true, margin: "10px" }}中的margin支持正负的百分比和px

custom给了更多的可能性

import { motion } from "framer-motion";const items = ["🍎", "🍌", "🍊", "🍇"];const itemVariants = {hidden: { opacity: 0, x: -50 },visible: (i) => ({opacity: 1,x: 0,transition: { delay: i * 0.1 }})
};export default function FruitList() {return (<div>{items.map((item, i) => (<motion.divkey={i}variants={itemVariants}initial="hidden"whileInView="visible"custom={i} // 传递索引控制延迟viewport={{ once: true, margin: "10px" }}style={{ margin: "20px" }}>{item}</motion.div>))}</div>);
}

元素离开屏幕检测方法

import { useRef, useEffect } from "react";
import { motion, useInView } from "framer-motion";const items = ["🍎", "🍌", "🍊", "🍇"];const itemVariants = {hidden: { opacity: 0, x: -50 },visible: (i) => ({opacity: 1,x: 0,transition: { delay: i * 0.1 }})
};export default function FruitList() {const ref = useRef(null);const isInView = useInView(ref); // 检测元素是否在视口内useEffect(() => {if (isInView) {console.log("元素111");// 在这里执行动画或逻辑} else {console.log("元素已离开视口");}}, [isInView]);return (<div ref={ref}>{items.map((item, i) => (<motion.divkey={i}variants={itemVariants}initial="hidden"whileInView="visible"custom={i} // 传递索引控制延迟viewport={{ once: true, margin: "10px" }}style={{ margin: "20px" }}>{item}</motion.div>))}</div>);
}

http://www.dtcms.com/a/492231.html

相关文章:

  • 英文字体展示网站推荐邯郸市官网
  • 《2D角色+3D场景:动漫游戏次元融合的技术突破路径》
  • 极海APM32F035无电解电容变频控制参考方案,助力智能家电实现低成本、高能效驱动
  • 视频网站开发流程女鞋网站建设策划方案
  • 海山免费网站建设山西p2p网站建设
  • 网站如何动态修改主页wordpress create a network
  • 网站开发案例详解下载wordpress转
  • 深圳网站建设最专业的铁路工程造价信息网
  • 【第5篇】向量化处理步骤
  • 打靶场的练习
  • 绍兴网站关键词优化免费的行情软件网站在线使用
  • 河南省台前县建设局网站公司展示型网站
  • 嘉兴平湖网站建设公司官网设计公司
  • 做高仿表网站容易被k吗在贸易网站怎么做贸易
  • 手机商城网站如何医学ppt模板免费下载
  • 辽阳网站seo南京网站销售
  • 做网站为什么一定要去国外企业管理培训公司排行榜
  • AOSP之Android Automotive
  • Flink ProcessFunction 与低层级 Join 实战手册:实时画像秒级更新系统
  • 公司网站后台维护wordpress 附件 标签
  • 全国网站建设企业信息管理与信息系统专业
  • 电商网站建设教案桂林阳朔楼盘最新价格
  • 四川建设信息共享网站网站根目录验证文件在哪里
  • 全球首个真实物理环境机器人基准测试发布,具身智能迎来统一评测标准
  • 菏泽郓城住房和城乡建设局网站wordpress付费制插件
  • QT/C++ TCP/IP服务端程序
  • Linux-> TCP 编程3
  • 前端的学习与实战(一)
  • 优惠的网站建设百度竞价推广开户多少钱
  • LeNet网络