圣诞节快要到啦,提前祝大家圣诞节快乐!!!
项目完整源码在最后哦✨
视频
(一):项目环境搭建
在这个教程中,我们将一步步创建一个精美的圣诞祝福网页。本文是系列的第一部分,我们将完成项目的环境搭建。
环境准备
1. Node.js安装
- 访问 Node.js官网
- 下载并安装LTS(长期支持)版本
- 验证安装:
node --version
npm --version
2. 开发工具
- 安装VSCode:下载地址
- 安装必要的VSCode插件:
- ESLint
- Prettier
- Tailwind CSS IntelliSense
- TypeScript Vue Plugin (Volar)
项目创建
1. 使用Vite创建项目
打开终端,执行以下命令:
# 创建项目
npm create vite@latest christmas-wishes -- --template react-ts# 进入项目目录
cd christmas-wishes# 安装依赖
npm install
2. 安装必要依赖
# 安装Tailwind CSS
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p# 安装Framer Motion动画库
npm install framer-motion# 安装其他工具库
npm install classnames @types/node
项目配置
1. 配置TypeScript
创建/更新tsconfig.json
:
{"compilerOptions": {"target": "ES2020","useDefineForClassFields": true,"lib": ["ES2020", "DOM", "DOM.Iterable"],"module": "ESNext","skipLibCheck": true,"moduleResolution": "bundler","allowImportingTsExtensions": true,"resolveJsonModule": true,"isolatedModules": true,"noEmit": true,"jsx": "react-jsx","strict": true,"noUnusedLocals": true,"noUnusedParameters": true,"noFallthroughCasesInSwitch": true,"baseUrl": ".","paths": {"@/*": ["src/*"]}},"include": ["src"],"references": [{ "path": "./tsconfig.node.json" }]
}
2. 配置Tailwind CSS
- 更新
tailwind.config.js
:
javascript">/** @type {import('tailwindcss').Config} */
export default {content: ["./index.html","./src/**/*.{js,ts,jsx,tsx}",],theme: {extend: {colors: {'christmas': {red: '#D42426',green: '#2F5233',gold: '#FFD700',},},animation: {'snow-fall': 'snow-fall 10s linear infinite','float': 'float 3s ease-in-out infinite','twinkle': 'twinkle 1.5s ease-in-out infinite','rotate': 'rotate 8s linear infinite','bounce-slow': 'bounce 3s infinite','sway': 'sway 6s ease-in-out infinite',},keyframes: {'snow-fall': {'0%': { transform: 'translateY(-10vh) translateX(0)' },'50%': { transform: 'translateY(45vh) translateX(20px)' },'100%': { transform: 'translateY(100vh) translateX(0)' },},'float': {'0%, 100%': { transform: 'translateY(0)' },'50%': { transform: 'translateY(-20px)' },},'twinkle': {'0%, 100%': { opacity: 1 },'50%': { opacity: 0.3 },},'rotate': {'0%': { transform: 'rotate(0deg)' },'100%': { transform: 'rotate(360deg)' },},'sway': {'0%, 100%': { transform: 'rotate(-3deg)' },'50%': { transform: 'rotate(3deg)' },},},},},plugins: [],
}
- 更新
src/index.css
:
@tailwind base;
@tailwind components;
@tailwind utilities;@layer base {body {@apply bg-blue-950 text-white min-h-screen overflow-hidden;}
}@layer components {.christmas-button {@apply px-6 py-3 rounded-full bg-gradient-to-r from-christmas-red to-christmas-greentext-white font-bold shadow-lg transform transition-all duration-300hover:scale-105 hover:shadow-xl focus:outline-none focus:ring-2 focus:ring-christmas-gold focus:ring-opacity-50;}.christmas-input {@apply w-full px-4 py-2 rounded-lg bg-white/10 border border-white/20text-white placeholder-white/50 focus:outline-none focus:ring-2focus:ring-christmas-gold focus:border-transparenttransition-all duration-300;}
}
3. 创建项目结构
- 目录结构说明:
src/
├── assets/ # 静态资源
│ └── audio/ # 音频文件
├── components/ # React组件
├── utils/ # 工具函数
├── App.tsx # 主应用组件
├── main.tsx # 入口文件
└── index.css # 全局样式
4. 添加音频资源
-
下载所需的音频文件:
- 背景音乐:Merry Christmas Mr. Lawrence
-
将下载的文件放入
src/assets/audio
目录
5. 验证环境
- 启动开发服务器:
npm run dev
-
访问控制台输出的URL(通常是 http://localhost:5173)
-
确认是否看到Vite的默认页面
(二):核心组件实现
在第一部分中,我们完成了项目环境的搭建。现在,让我们开始实现核心组件。我们将一步步创建每个组件,并确保它们能够正常工作。
1. 交互式雪花效果
1.1 创建基础组件
创建文件src/components/InteractiveSnow.tsx
:
typescript">import { useEffect, useRef, useState } from 'react';
import { motion } from 'framer-motion';interface Snowflake {id: number;x: number;y: number;size: number;opacity: number;delay: number;
}export const InteractiveSnow = () => {const [snowflakes, setSnowflakes] = useState<Snowflake[]>([]);const [mousePosition, setMousePosition] = useState({ x: 0, y: 0 });const containerRef = useRef<HTMLDivElement>(null);const requestRef = useRef<number>();const previousTimeRef = useRef<number>();return (<div ref={containerRef}className="fixed inset-0 pointer-events-none overflow-hidden">{/* 雪花将在这里渲染 */}</div>);
};
1.2 生成雪花
添加雪花生成逻辑:
typescript">// 在InteractiveSnow组件中添加
useEffect(() => {// 生成50个雪花const flakes = Array.from({ length: 50 }, (_, i) => ({id: i,x: Math.random() * 100,y: Math.random() * 100,size: Math.random() * 8 + 10,opacity: Math.random() * 0.5 + 0.3,delay: Math.random() * 10,}));setSnowflakes(flakes);
}, []);
1.3 添加鼠标交互
实现鼠标跟踪:
typescript">// 在InteractiveSnow组件中添加
useEffect(() => {const handleMouseMove = (event: MouseEvent) => {if (containerRef.current) {const rect = containerRef.current.getBoundingClientRect();setMousePosition({x: event.clientX - rect.left,y: event.clientY - rect.top,});}};window.addEventListener('mousemove', handleMouseMove);return () => window.removeEventListener('mousemove', handleMouseMove);
}, []);
1.4 实现动画循环
添加动画更新逻辑:
typescript">// 在InteractiveSnow组件中添加
const animate = (time: number) => {if (previousTimeRef.current !== undefined) {setSnowflakes(prevFlakes => prevFlakes.map(flake => {let newX = flake.x;let newY = flake.y;// 基础下落运动newY = (newY + 0.2) % 100;// 计算与鼠标的距离const dx = (mousePosition.x / (containerRef.current?.clientWidth || 1)) * 100 - flake.x;const dy = (mousePosition.y / (containerRef.current?.clientHeight || 1)) * 100 - flake.y;const distance = Math.sqrt(dx * dx + dy * dy);// 鼠标交互效果if (distance < 30) {const angle = Math.atan2(dy, dx);const force = (30 - distance) / 30 * 0.15;newX += Math.cos(angle) * force;newY += Math.sin(angle) * force;}// 随机漂移newX += Math.sin(time / 2000 + flake.delay) * 0.05;// 确保在视口内newX = ((newX + 100) % 100);newY = ((newY + 100) % 100);return {...flake,x: newX,y: newY,};}));}previousTimeRef.current = time;requestRef.current = requestAnimationFrame(animate);
};useEffect(() => {requestRef.current = requestAnimationFrame(animate);return () => {if (requestRef.current) {cancelAnimationFrame(requestRef.current);}};
}, [mousePosition]);
1.5 渲染雪花
更新渲染部分:
typescript">// 在InteractiveSnow组件的return语句中
return (<div ref={containerRef}className="fixed inset-0 pointer-events-none overflow-hidden">{snowflakes.map((flake) => (<motion.divkey={flake.id}className="absolute text-white select-none"style={{left: `${flake.x}%`,top: `${flake.y}%`,fontSize: `${flake.size}px`,opacity: flake.opacity,filter: 'blur(0.3px)',}}>❄️</motion.div>))}</div>
);
2. 音频控制器
2.1 创建基础组件
创建文件src/components/AudioController.tsx
:
typescript">import { useEffect, useRef, useState } from 'react';export const AudioController: React.FC = () => {const [isPlaying, setIsPlaying] = useState(false);const audioRef = useRef<HTMLAudioElement | null>(null);return (<buttononClick={() => setIsPlaying(!isPlaying)}className="fixed top-4 right-4 z-50 p-2 rounded-full bg-white/10 hover:bg-white/20 transition-colors duration-300">{isPlaying ? '🔊' : '🔈'}</button>);
};
2.2 添加音频控制
更新音频控制逻辑:
typescript">// 在AudioController组件中添加
useEffect(() => {audioRef.current = new Audio('/src/assets/audio/Merry Christmas Mr. Lawrence.mp3');audioRef.current.loop = true;return () => {if (audioRef.current) {audioRef.current.pause();audioRef.current = null;}};
}, []);useEffect(() => {if (audioRef.current) {if (isPlaying) {audioRef.current.play().catch(() => {setIsPlaying(false);});} else {audioRef.current.pause();}}
}, [isPlaying]);
2.3 添加音效功能
创建文件src/utils/audio.ts
:
typescript">export const playBellSound = () => {const audio = new Audio('/src/assets/audio/bell-sound.mp3');audio.volume = 0.5;audio.play().catch(console.error);
};
3. 圣诞装饰元素
3.1 创建基础组件
创建文件src/components/ChristmasElements.tsx
:
typescript">import { motion } from 'framer-motion';export const Decorations = () => {return (<div className="fixed inset-0 pointer-events-none"><ChristmasTree /><Santa /><Gifts /><Stars /><Bells /><CandyCanes /><ChristmasSocks /></div>);
};
3.2 实现装饰元素
在同一文件中添加各个装饰元素:
typescript">const ChristmasTree = () => (<motion.divclassName="absolute bottom-10 left-10 text-6xl"animate={{y: [0, -10, 0],rotate: [-2, 2, -2],}}transition={{duration: 4,repeat: Infinity,ease: "easeInOut"}}>🎄</motion.div>
);const Santa = () => (<motion.divclassName="absolute top-20 right-20 text-5xl"animate={{x: [0, -100, 0],y: [0, 20, 0],}}transition={{duration: 10,repeat: Infinity,ease: "linear"}}>🎅</motion.div>
);const Gifts = () => (<motion.divclassName="absolute bottom-20 right-20 text-4xl"animate={{scale: [1, 1.1, 1],rotate: [-5, 5, -5],}}transition={{duration: 3,repeat: Infinity,ease: "easeInOut"}}>🎁</motion.div>
);// ... 其他装饰元素
3.3 添加更多装饰
继续添加其他装饰元素:
typescript">const Stars = () => (<motion.divclassName="absolute top-10 left-20 text-3xl"animate={{scale: [1, 1.2, 1],opacity: [1, 0.5, 1],}}transition={{duration: 2,repeat: Infinity,ease: "easeInOut"}}>⭐</motion.div>
);const Bells = () => (<motion.divclassName="absolute top-40 left-40 text-4xl"animate={{rotate: [-10, 10, -10],}}transition={{duration: 2,repeat: Infinity,ease: "easeInOut"}}>🔔</motion.div>
);const CandyCanes = () => (<motion.divclassName="absolute bottom-40 left-30 text-4xl"animate={{y: [0, -5, 0],}}transition={{duration: 3,repeat: Infinity,ease: "easeInOut"}}>🍬</motion.div>
);const ChristmasSocks = () => (<motion.divclassName="absolute bottom-30 right-40 text-4xl"animate={{rotate: [-5, 5, -5],}}transition={{duration: 4,repeat: Infinity,ease: "easeInOut"}}>🧦</motion.div>
);
(三):主应用实现
在前两个部分中,我们完成了项目环境搭建和核心组件的实现。现在,让我们实现主应用逻辑,将所有组件组合在一起,并添加祝福语生成功能。
1. 祝福语生成器
1.1 创建祝福语工具
创建文件src/utils/wishesGenerator.ts
:
typescript">const wishes = ["愿平安夜的星光为你点亮前行的道路,愿圣诞节的祝福为你带来温暖与希望。🌟✨","在这个飘雪的季节,愿圣诞老人把最美好的祝福悄悄放进你的梦里,伴你度过一个温馨难忘的圣诞节。🎅❄️","愿圣诞的钟声带给你欢乐,愿圣诞的雪花带给你纯净,愿圣诞的烛光带给你温暖。🔔❄️🕯️","圣诞快乐!愿你的生活如圣诞树般绚丽多彩,如圣诞铃铛般充满欢乐。🎄🔔","愿这个圣诞节带给你甜蜜的祝福和温馨的问候,让你感受到节日的快乐与温暖。🎁💝",
];export const getRandomWish = (): string => {const randomIndex = Math.floor(Math.random() * wishes.length);return wishes[randomIndex];
};export const playBellSound = () => {const audio = new Audio('/src/assets/audio/bell-sound.mp3');audio.volume = 0.5;audio.play().catch(console.error);
};
2. 主应用组件
2.1 创建主应用
更新src/App.tsx
:
typescript">import { useState } from 'react'
import { motion, AnimatePresence } from 'framer-motion'
import { Decorations } from './components/ChristmasElements'
import { AudioController } from './components/AudioController'
import { InteractiveSnow } from './components/InteractiveSnow'
import { getRandomWish, playBellSound } from './utils/wishesGenerator'function ChristmasWishes() {const [name, setName] = useState('')const [showWishes, setShowWishes] = useState(false)const [currentWish, setCurrentWish] = useState('')const handleSubmit = (e: React.FormEvent) => {e.preventDefault()if (name.trim()) {setCurrentWish(getRandomWish())setShowWishes(true)playBellSound()}}return (<div className="min-h-screen flex flex-col items-center justify-center p-4 relative overflow-hidden bg-gradient-to-br from-blue-950 via-blue-900 to-blue-950">{/* 背景效果 */}<div className="absolute inset-0 bg-[radial-gradient(circle_at_50%_50%,rgba(255,255,255,0.05),transparent)] pointer-events-none" /><div className="absolute inset-0 bg-gradient-to-b from-transparent via-blue-950/30 to-blue-950/50" />{/* 组件 */}<AudioController /><InteractiveSnow /><Decorations />{/* 主要内容 */}<div className="text-center z-10 max-w-2xl mx-auto px-4"><AnimatePresence mode="wait">{!showWishes ? (<motion.divkey="input"initial={{ opacity: 0, y: 20 }}animate={{ opacity: 1, y: 0 }}exit={{ opacity: 0, y: -20 }}><motion.h1className="text-4xl md:text-5xl font-bold mb-8 text-white"animate={{ scale: [1, 1.05, 1] }}transition={{ duration: 2, repeat: Infinity }}>🎄 圣诞快乐 🎄</motion.h1><p className="text-lg text-white/80 mb-8">分享你的圣诞祝福</p><form onSubmit={handleSubmit} className="space-y-6"><inputtype="text"value={name}onChange={(e) => setName(e.target.value)}placeholder="输入你的名字"className="christmas-input"required/><buttontype="submit"className="christmas-button">生成祝福</button></form></motion.div>) : (<motion.divkey="wishes"className="text-center"initial={{ opacity: 0, scale: 0.8 }}animate={{ opacity: 1, scale: 1 }}exit={{ opacity: 0, scale: 1.2 }}><div className="bg-white/10 backdrop-blur-sm rounded-xl p-8 shadow-xl"><p className="text-xl mb-4">致 {name}:</p><p className="text-2xl mb-6">{currentWish}</p><buttononClick={() => setShowWishes(false)}className="christmas-button">返回</button></div></motion.div>)}</AnimatePresence></div></div>)
}export default ChristmasWishes
2.2 更新入口文件
更新src/main.tsx
:
typescript">import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'ReactDOM.createRoot(document.getElementById('root')!).render(<React.StrictMode><App /></React.StrictMode>,
)
总结
恭喜!你已经成功创建了一个完整的圣诞祝福网页应用。这个应用包含:
- 交互式雪花效果
- 背景音乐控制
- 圣诞装饰动画
- 祝福语生成功能
- 平滑的页面过渡
- 响应式设计
- 错误处理机制
项目源码:
GitHub链接
Gitee链接
祝你圣诞快乐!🎄✨