news 2025/12/20 4:33:09

前端动画的多种实现方式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
前端动画的多种实现方式

动画的本质是把内容的两个状态做平滑的过渡(中间状态的展示)

import React, { useEffect, useRef, useState } from 'react'; import './styles.css'; // 动画实践 // 1.1 translation const TranslationDemo = () => { return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>1.1 CSS Translation</h3> <div className="translation-box" style={{ width: '100px', height: '100px', backgroundColor: '#3498db', transition: 'transform 1s ease-in-out', cursor: 'pointer' }} onMouseEnter={(e) => { e.currentTarget.style.transform = 'translateX(200px)'; }} onMouseLeave={(e) => { e.currentTarget.style.transform = 'translateX(0)'; }} > Hover me </div> </div> ); }; // 1.2 animation + @keyframes const KeyframesDemo = () => { return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>1.2 CSS Animation + @keyframes</h3> <div className="keyframes-box" style={{ width: '100px', height: '100px', backgroundColor: '#e74c3c', animation: 'bounce 2s infinite' }} > Bouncing </div> <style>{` @keyframes bounce { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-50px); } } `}</style> </div> ); }; // 2.1 requestAnimationFrame const RequestAnimationFrameDemo = () => { const boxRef = useRef<HTMLDivElement>(null); const [isAnimating, setIsAnimating] = useState(false); const animationRef = useRef<number>(); const animate = () => { if (boxRef.current) { const currentX = parseFloat(boxRef.current.style.left || '0'); if (currentX < 300) { boxRef.current.style.left = `${currentX + 2}px`; animationRef.current = requestAnimationFrame(animate); } else { boxRef.current.style.left = '0px'; setIsAnimating(false); } } }; const startAnimation = () => { if (!isAnimating) { setIsAnimating(true); animate(); } }; useEffect(() => { return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, []); return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>2.1 requestAnimationFrame</h3> <div style={{ position: 'relative', height: '120px' }}> <div ref={boxRef} style={{ position: 'absolute', left: '0px', width: '100px', height: '100px', backgroundColor: '#2ecc71' }} > RAF </div> </div> <button onClick={startAnimation} disabled={isAnimating}> Start Animation </button> </div> ); }; // 3.1 Canvas + requestAnimationFrame const CanvasDemo = () => { const canvasRef = useRef<HTMLCanvasElement>(null); const animationRef = useRef<number>(); const xRef = useRef(0); const [isRunning, setIsRunning] = useState(false); const draw = () => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; // 清空画布 ctx.clearRect(0, 0, canvas.width, canvas.height); // 绘制圆形 ctx.fillStyle = '#9b59b6'; ctx.beginPath(); ctx.arc(xRef.current, 50, 20, 0, Math.PI * 2); ctx.fill(); // 更新位置 xRef.current += 2; if (xRef.current > canvas.width) { xRef.current = 0; } animationRef.current = requestAnimationFrame(draw); }; const toggleAnimation = () => { if (isRunning) { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } setIsRunning(false); } else { draw(); setIsRunning(true); } }; useEffect(() => { return () => { if (animationRef.current) { cancelAnimationFrame(animationRef.current); } }; }, []); return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>3.1 Canvas + requestAnimationFrame</h3> <canvas ref={canvasRef} width={400} height={100} style={{ border: '1px solid #000' }} /> <div> <button onClick={toggleAnimation}> {isRunning ? 'Pause' : 'Start'} </button> </div> </div> ); }; // 4.1 SVG + CSS / SMIL / JS const SVGDemo = () => { const [rotate, setRotate] = useState(0); useEffect(() => { const interval = setInterval(() => { setRotate(prev => (prev + 5) % 360); }, 50); return () => clearInterval(interval); }, []); return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>4.1 SVG Animation</h3> <svg width="200" height="200"> {/* CSS Animation */} <circle cx="50" cy="50" r="20" fill="#e67e22"> <animate attributeName="r" values="20;30;20" dur="2s" repeatCount="indefinite" /> </circle> {/* JS Animation */} <rect x="100" y="30" width="40" height="40" fill="#1abc9c" transform={`rotate(${rotate} 120 50)`} /> </svg> </div> ); }; // 5.1 GSAP const GSAPDemo = () => { const gsapRef = useRef<HTMLDivElement>(null); const animateWithGSAP = () => { // 注意: 需要安装 gsap 库: npm install gsap // import gsap from 'gsap'; // gsap.to(gsapRef.current, { x: 200, duration: 1, ease: 'power2.inOut' }); // 简化版演示 (不依赖GSAP库) if (gsapRef.current) { gsapRef.current.style.transition = 'transform 1s ease-in-out'; gsapRef.current.style.transform = 'translateX(200px)'; setTimeout(() => { if (gsapRef.current) { gsapRef.current.style.transform = 'translateX(0)'; } }, 1000); } }; return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>5.1 GSAP (简化演示)</h3> <div ref={gsapRef} style={{ width: '100px', height: '100px', backgroundColor: '#f39c12' }} > GSAP </div> <button onClick={animateWithGSAP}>Animate</button> </div> ); }; // 5.2 Framer Motion const FramerMotionDemo = () => { const [isVisible, setIsVisible] = useState(true); return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>5.2 Framer Motion (简化演示)</h3> {/* 注意: 需要安装 framer-motion: npm install framer-motion */} {/* import { motion } from 'framer-motion'; */} <div style={{ width: '100px', height: '100px', backgroundColor: '#c0392b', opacity: isVisible ? 1 : 0, transform: isVisible ? 'scale(1)' : 'scale(0.5)', transition: 'all 0.5s ease-in-out' }} > Framer </div> <button onClick={() => setIsVisible(!isVisible)}> Toggle </button> </div> ); }; // 6.1 Web Animations API const WebAnimationsAPIDemo = () => { const wapiRef = useRef<HTMLDivElement>(null); const animateWithWAPI = () => { if (wapiRef.current) { wapiRef.current.animate([ { transform: 'translateX(0) rotate(0deg)', backgroundColor: '#16a085' }, { transform: 'translateX(200px) rotate(360deg)', backgroundColor: '#27ae60' } ], { duration: 1000, easing: 'ease-in-out', iterations: 1, fill: 'forwards' }); setTimeout(() => { if (wapiRef.current) { wapiRef.current.animate([ { transform: 'translateX(200px) rotate(360deg)', backgroundColor: '#27ae60' }, { transform: 'translateX(0) rotate(0deg)', backgroundColor: '#16a085' } ], { duration: 1000, easing: 'ease-in-out', fill: 'forwards' }); } }, 1000); } }; return ( <div style={{ padding: '20px', border: '1px solid #ccc', margin: '10px' }}> <h3>6.1 Web Animations API</h3> <div ref={wapiRef} style={{ width: '100px', height: '100px', backgroundColor: '#16a085' }} > WAAPI </div> <button onClick={animateWithWAPI}>Animate</button> </div> ); }; // 主组件 const AnimationPractice = () => { return ( <div style={{ padding: '20px', fontFamily: 'Arial, sans-serif' }}> <h1>动画实践合集</h1> <TranslationDemo /> <KeyframesDemo /> <RequestAnimationFrameDemo /> <CanvasDemo /> <SVGDemo /> <GSAPDemo /> <FramerMotionDemo /> <WebAnimationsAPIDemo /> </div> ); }; export default AnimationPractice;

CSS

JS

Canvas(脱离DOM)

SVG(结构化+矢量)

动画库

浏览器Web Animations API

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2025/12/14 13:47:35

29、脚本编写与项目构建全攻略

脚本编写与项目构建全攻略 命令选项与格式优化 在Linux命令行操作中,许多命令都有短选项和长选项两种形式。以 ls 命令为例: - [me@linuxbox ~]$ ls -ad - [me@linuxbox ~]$ ls --all --directory 这两条命令是等效的。在命令行输入选项时,为了减少输入量,通常会…

作者头像 李华
网站建设 2025/12/14 13:47:04

36、编程中的运算符、数组及高精度计算

编程中的运算符、数组及高精度计算 1. 自增和自减运算符 自增( ++ )和自减( -- )运算符在编程中十分常见,在bash等编程语言中也有应用。这些运算符可以放在参数的前面或后面,虽然它们都能将参数的值加1或减1,但放置位置不同会有细微差别。 - 前置运算符 :当运…

作者头像 李华
网站建设 2025/12/14 13:45:24

图像像素RGBA提取器 v2.0.0 - 精确提取图像颜色数据的专业工具

什么是图像像素RGBA提取器&#xff1f; 图像像素RGBA提取器是一款功能强大的在线工具&#xff0c;专为需要精确获取图像颜色数据的用户设计。它可以从上传的图像中提取每个像素的RGBA值&#xff08;红、绿、蓝、透明度&#xff09;&#xff0c;并将结果导出为CSV格式&#xff…

作者头像 李华
网站建设 2025/12/14 13:45:18

dll一键修复工具win11版,专为win11打造

dll一键修复工具win11是一款专为windows11所推出的dll修复工具。 该软件自带一键自动修复和手动修复两大功能&#xff0c;可根据用户不同的需求来为用户提供完全不一样的功能&#xff0c;轻松解决电脑中丢失DLL文件或缺少某个组件等DLL常见错误问题。 该软件自带一键自动修复…

作者头像 李华
网站建设 2025/12/14 13:44:58

50、Korn Shell编程:条件判断、字符串与文件测试及循环结构

Korn Shell编程:条件判断、字符串与文件测试及循环结构 逻辑表达式与条件语句 在使用由逻辑与运算符(&&)或逻辑或运算符(||)连接的命令组成的逻辑表达式时,需要记住以下两点: 1. 如果两个命令通过逻辑与运算符连接,只有当第一个命令的结果为真时,shell才会…

作者头像 李华
网站建设 2025/12/14 13:44:52

53、Korn Shell编程全面指南

Korn Shell编程全面指南 1. Korn Shell基础介绍 Korn Shell(ksh)是由贝尔实验室的David Korn创建的命令和脚本语言。它具有众多实用的特性,以下为你详细介绍: - 命令行编辑 :支持类似于Unix编辑器vi和emacs的命令行编辑功能,让用户可以方便地修改输入的命令。 - 文…

作者头像 李华