From 8ef173c7d836c382f9c33d299c5c8e52f6447530 Mon Sep 17 00:00:00 2001 From: hongjli <3117313295@qq.com> Date: 星期二, 08 四月 2025 11:19:57 +0800 Subject: [PATCH] 主页优化 --- src/app/layout.tsx | 4 src/components/SupplyChainAIMindMap.tsx | 117 +++++++++++++++------- src/app/globals.css | 67 +++++++++++++ src/app/page.tsx | 65 +++++++----- 4 files changed, 182 insertions(+), 71 deletions(-) diff --git a/src/app/globals.css b/src/app/globals.css index 25d60dc..8ce8f4c 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -13,6 +13,11 @@ /* 鍩虹棰滆壊璁剧疆 */ --background: var(--ai-surface); --foreground: #1E2B63; + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 10, 16, 51; + --background-end-rgb: 0, 0, 0; + --scrollbar-track: rgba(30, 43, 99, 0.1); + --scrollbar-thumb: rgba(106, 219, 255, 0.3); } @theme inline { @@ -26,13 +31,71 @@ :root { --background: var(--ai-dark); --foreground: #E9EFFD; + --foreground-rgb: 255, 255, 255; + --background-start-rgb: 0, 0, 0; + --background-end-rgb: 0, 0, 0; } } body { - background: var(--background); - color: var(--foreground); + background: linear-gradient(to bottom, + rgb(var(--background-start-rgb)), + rgb(var(--background-end-rgb))); + color: rgb(var(--foreground-rgb)); font-family: 'PingFang SC', 'Microsoft YaHei', Arial, sans-serif; + min-height: 100vh; +} + +/* 婊氬姩鎬ц兘浼樺寲 */ +* { + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +html, body { + scroll-behavior: smooth; +} + +/* 鍚敤纭欢鍔犻�� */ +.will-change-transform, +.motion-safe\:will-change-transform, +.motion-safe\:hover\:will-change-transform:hover, +canvas { + will-change: transform, opacity; + transform: translateZ(0); + backface-visibility: hidden; +} + +/* 浼樺寲婊氬姩鏉� */ +::-webkit-scrollbar { + width: 10px; +} + +::-webkit-scrollbar-track { + background: var(--scrollbar-track); +} + +::-webkit-scrollbar-thumb { + background: var(--scrollbar-thumb); + border-radius: 5px; +} + +::-webkit-scrollbar-thumb:hover { + background: rgba(106, 219, 255, 0.5); +} + +/* 婊氬姩浼樺寲绫� */ +.smooth-scroll { + overflow-y: scroll; + scroll-behavior: smooth; + -webkit-overflow-scrolling: touch; +} + +/* 闃叉杩囧害閲嶆帓鍜岄噸缁� */ +.motion-reduce { + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; } /* 瀵艰埅鏍忕壒鏁堟牱寮� */ diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 42b3ae8..8ad4198 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -20,8 +20,8 @@ children: React.ReactNode; }) { return ( - <html lang="zh"> - <body className={inter.className}> + <html lang="zh-CN" className="smooth-scroll"> + <body className={`${inter.className} overflow-x-hidden`}> <ClientLayoutContent>{children}</ClientLayoutContent> </body> </html> diff --git a/src/app/page.tsx b/src/app/page.tsx index f380896..6223957 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -17,22 +17,22 @@ // 瀹氫箟鍔ㄧ敾鍙樹綋 const fadeInUp = { hidden: { opacity: 0, y: 50 }, - visible: { opacity: 1, y: 0, transition: { duration: 0.8, ease: "easeOut" } } + visible: { opacity: 1, y: 0, transition: { duration: 0.6, ease: "easeOut" } } }; const fadeInLeft = { hidden: { opacity: 0, x: -100 }, - visible: { opacity: 1, x: 0, transition: { duration: 0.7, ease: [0.25, 0.1, 0.25, 1] } } + visible: { opacity: 1, x: 0, transition: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1] } } }; const fadeInRight = { hidden: { opacity: 0, x: 100 }, - visible: { opacity: 1, x: 0, transition: { duration: 0.7, ease: [0.25, 0.1, 0.25, 1] } } + visible: { opacity: 1, x: 0, transition: { duration: 0.5, ease: [0.25, 0.1, 0.25, 1] } } }; const fadeInScale = { hidden: { opacity: 0, scale: 0.95 }, - visible: { opacity: 1, scale: 1, transition: { duration: 0.8, ease: "easeOut" } } + visible: { opacity: 1, scale: 1, transition: { duration: 0.6, ease: "easeOut" } } }; // 鎸夐挳鍑哄満鍔ㄧ敾 @@ -42,8 +42,8 @@ opacity: 1, y: 0, transition: { - delay: i * 0.2, - duration: 0.6, + delay: i * 0.15, + duration: 0.4, ease: [0.25, 0.1, 0.25, 1], }, }), @@ -60,20 +60,22 @@ {/* 鍏徃鍚嶇О鍜岀洰鏍囨弿杩� */} <motion.div initial={{ opacity: 0, y: 30 }} - animate={{ opacity: 1, y: 0 }} - transition={{ duration: 0.8, ease: "easeOut" }} - className="text-center mb-32 relative" + whileInView={{ opacity: 1, y: 0 }} + viewport={{ once: false, margin: "-100px" }} + transition={{ duration: 0.6, ease: "easeOut" }} + className="text-center mb-32 relative will-change-transform" > {/* 鑳屾櫙瑁呴グ鏁堟灉 */} <div className="absolute inset-0 -z-10 overflow-hidden pointer-events-none"> <motion.div className="absolute top-1/2 left-0 right-0 h-[1px] bg-gradient-to-r from-transparent via-[#6ADBFF]/30 to-transparent" initial={{ scaleX: 0 }} - animate={{ scaleX: 1 }} + whileInView={{ scaleX: 1 }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 1.2, delay: 0.3 }} /> <div className="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"> - {[...Array(3)].map((_, i) => ( + {[...Array(2)].map((_, i) => ( <motion.div key={i} className="absolute rounded-full border border-[#6ADBFF]/20" @@ -82,9 +84,11 @@ top: "50%", width: "160px", height: "160px", + willChange: "transform, opacity" }} initial={{ scale: 0, x: "-50%", y: "-50%", opacity: 0.1 }} - animate={{ scale: [0, 5 + i], opacity: [0.2, 0] }} + whileInView={{ scale: [0, 5 + i], opacity: [0.2, 0] }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 3, repeat: Infinity, @@ -98,7 +102,8 @@ <motion.h1 className="text-4xl md:text-5xl font-bold mb-3 relative inline-block" initial={{ opacity: 0, filter: "blur(10px)" }} - animate={{ opacity: 1, filter: "blur(0px)" }} + whileInView={{ opacity: 1, filter: "blur(0px)" }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 0.8, delay: 0.2 }} > <span className="text-transparent bg-clip-text bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB] relative"> @@ -122,7 +127,8 @@ <motion.div className="absolute inset-0 bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB]" initial={{ scaleX: 0 }} - animate={{ scaleX: 1 }} + whileInView={{ scaleX: 1 }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 0.8, delay: 0.5, ease: "easeOut" }} style={{ originX: 0 }} /> @@ -131,14 +137,16 @@ <motion.div className="text-gray-300 max-w-2xl mx-auto text-lg relative" initial={{ opacity: 0, y: 10 }} - animate={{ opacity: 1, y: 0 }} + whileInView={{ opacity: 1, y: 0 }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 0.6, delay: 0.7 }} > 鏅鸿兘鍖栦緵搴旈摼绠$悊锛� <motion.span className="inline-block text-[#6ADBFF] px-1" initial={{ opacity: 0 }} - animate={{ opacity: 1 }} + whileInView={{ opacity: 1 }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 0.4, delay: 1.1 }} > AI妯℃嫙APS鍦烘櫙 @@ -149,7 +157,8 @@ <motion.div className="absolute left-1/2 bottom-[-22px] w-16 h-[2px] -translate-x-1/2" initial={{ scale: 0 }} - animate={{ scale: 1 }} + whileInView={{ scale: 1 }} + viewport={{ once: false, margin: "-100px" }} transition={{ duration: 0.5, delay: 1.2 }} > <div className="w-full h-full bg-gradient-to-r from-[#6ADBFF]/0 via-[#6ADBFF] to-[#6ADBFF]/0"></div> @@ -164,10 +173,10 @@ custom={0} initial="hidden" whileInView="visible" - viewport={{ once: false, margin: "-150px" }} + viewport={{ once: false, margin: "-100px" }} variants={buttonVariants} whileTap={{ scale: 0.97, transition: { duration: 0.1 } }} - className="group relative" + className="group relative will-change-transform" > <div className="absolute -inset-0.5 rounded-xl bg-gradient-to-r from-[#6ADBFF] to-[#5E72EB] opacity-30 blur group-hover:opacity-100 group-hover:blur-md transition-all duration-500 group-hover:duration-200 group-active:opacity-70"></div> <div className="relative flex items-center gap-2 px-10 py-4 rounded-lg backdrop-blur-sm bg-[#131C41]/90 border border-[#6ADBFF]/30 transition-all duration-300 shadow-[0_0_15px_rgba(106,219,255,0.15)] group-hover:shadow-[0_0_25px_rgba(106,219,255,0.25)] group-active:shadow-[0_0_10px_rgba(106,219,255,0.3)]"> @@ -204,10 +213,10 @@ custom={1} initial="hidden" whileInView="visible" - viewport={{ once: false, margin: "-150px" }} + viewport={{ once: false, margin: "-100px" }} variants={buttonVariants} whileTap={{ scale: 0.97, transition: { duration: 0.1 } }} - className="group relative" + className="group relative will-change-transform" > <div className="absolute -inset-0.5 rounded-xl bg-gradient-to-r from-[#FF6A88] to-[#5E72EB] opacity-30 blur group-hover:opacity-100 group-hover:blur-md transition-all duration-500 group-hover:duration-200 group-active:opacity-70"></div> <div className="relative flex items-center gap-2 px-10 py-4 rounded-lg backdrop-blur-sm bg-[#131C41]/90 border border-[#FF6A88]/30 transition-all duration-300 shadow-[0_0_15px_rgba(255,106,136,0.15)] group-hover:shadow-[0_0_25px_rgba(255,106,136,0.25)] group-active:shadow-[0_0_10px_rgba(255,106,136,0.3)]"> @@ -272,9 +281,9 @@ <motion.div initial="hidden" whileInView="visible" - viewport={{ once: false, margin: "-150px" }} + viewport={{ once: false, margin: "-100px" }} variants={fadeInLeft} - className="relative" + className="relative will-change-transform" > <div className="absolute -left-3 top-0 h-full w-1 bg-gradient-to-b from-[#6ADBFF] via-[#5E72EB] to-transparent"></div> <div className="backdrop-blur-sm bg-white/5 rounded-xl p-8 border border-[#6ADBFF]/20 h-full"> @@ -289,9 +298,9 @@ <motion.div initial="hidden" whileInView="visible" - viewport={{ once: false, margin: "-150px" }} + viewport={{ once: false, margin: "-100px" }} variants={fadeInRight} - className="relative" + className="relative will-change-transform" > <div className="absolute -left-3 top-0 h-full w-1 bg-gradient-to-b from-[#FF6A88] via-[#5E72EB] to-transparent"></div> <div className="backdrop-blur-sm bg-white/5 rounded-xl p-8 border border-[#FF6A88]/20 h-full"> @@ -307,9 +316,9 @@ <motion.div initial={{ opacity: 0, y: 40 }} whileInView={{ opacity: 1, y: 0 }} - viewport={{ once: false, margin: "-150px" }} - transition={{ duration: 0.7, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }} - className="mt-20 w-full grid grid-cols-2 md:grid-cols-4 gap-8" + viewport={{ once: false, margin: "-100px" }} + transition={{ duration: 0.5, ease: [0.25, 0.1, 0.25, 1], delay: 0.2 }} + className="mt-20 w-full grid grid-cols-2 md:grid-cols-4 gap-8 will-change-transform" > <div className="text-center"> <div className="text-4xl font-bold text-[#6ADBFF] mb-2">98%</div> diff --git a/src/components/SupplyChainAIMindMap.tsx b/src/components/SupplyChainAIMindMap.tsx index 7646d4c..b69cb9d 100644 --- a/src/components/SupplyChainAIMindMap.tsx +++ b/src/components/SupplyChainAIMindMap.tsx @@ -14,6 +14,14 @@ export default function SupplyChainAIMindMap() { const canvasRef = useRef<HTMLCanvasElement>(null); + const nodesRef = useRef<Node[]>([ + { x: 0.15, y: 0.3, label: '閲囪喘', color: '#6ADBFF', icon: '馃摝' }, + { x: 0.35, y: 0.3, label: '鐢熶骇', color: '#5E72EB', icon: '馃彮' }, + { x: 0.65, y: 0.3, label: '閰嶉��', color: '#FF6A88', icon: '馃殮' }, + { x: 0.85, y: 0.3, label: '瀹㈡埛', color: '#FF9D6A', icon: '馃懃' }, + { x: 0.85, y: 0.6, label: '闇�姹傞娴�', color: '#FF6A88', icon: '馃搳' }, + { x: 0.5, y: 0.5, label: '鏅鸿兘鍒嗘瀽寮曟搸', color: '#5E72EB', isAI: true }, + ]); useEffect(() => { const canvas = canvasRef.current; @@ -88,17 +96,22 @@ targetY: endY, size: Math.random() * 2 + 1, color: path.color, - speed: 0.5 + Math.random() * 1, + speed: 0.5 + Math.random() * 0.5, // 闄嶄綆閫熷害 energy: 1, phase: Math.random() * Math.PI * 2, - orbitRadius: Math.random() * 20 + 10, - orbitSpeed: (Math.random() * 0.1 + 0.05) * (Math.random() < 0.5 ? 1 : -1), + orbitRadius: Math.random() * 15 + 5, // 鍑忓皬杞ㄩ亾鍗婂緞 + orbitSpeed: (Math.random() * 0.08 + 0.03) * (Math.random() < 0.5 ? 1 : -1), // 闄嶄綆杞ㄩ亾閫熷害 pathIndex, lifespan: 0, - maxLifespan: 150 + Math.random() * 100 + maxLifespan: 150 + Math.random() * 50 // 鍑忓皯鏈�澶у鍛� }; particles.push(particle); + + // 闄愬埗绮掑瓙鎬绘暟锛岄槻姝㈡�ц兘闂 + if (particles.length > 30) { + particles.shift(); + } }; // 鏇存柊閲忓瓙绮掑瓙 @@ -152,10 +165,18 @@ // 缁樺埗鍦烘櫙 const drawScene = () => { + if (!ctx) return; + + // 娓呴櫎鐢诲竷 ctx.clearRect(0, 0, canvas.width, canvas.height); - // 缁樺埗绉戞妧鎰熻儗鏅� - drawTechBackground(); + // 鍑忓皯閲嶅璁$畻锛岄鍏堣绠楀父鐢ㄥ�� + const canvasWidth = canvas.width; + const canvasHeight = canvas.height; + const time = Date.now() * 0.001; + + // 缁樺埗鎶�鏈儗鏅� + drawTechBackground(ctx, canvasWidth, canvasHeight, time); // 缁樺埗鑳介噺鍦鸿矾寰� drawEnergyFields(); @@ -165,46 +186,52 @@ // 缁樺埗閲忓瓙绮掑瓙 drawQuantumParticles(); + + // 缁樺埗AI鑺傜偣 + const aiNode = nodesRef.current.find(node => node.isAI); + if (aiNode) { + drawAINode(aiNode.x * canvasWidth, aiNode.y * canvasHeight); + } }; // 缁樺埗绉戞妧鎰熻儗鏅� - const drawTechBackground = () => { + const drawTechBackground = (ctx: CanvasRenderingContext2D, canvasWidth: number, canvasHeight: number, time: number) => { const gridSize = 40; - const time = Date.now() * 0.001; - // 缁樺埗鍔ㄦ�佺綉鏍� + // 闄嶄綆缃戞牸瀵嗗害锛屼粎缁樺埗杈冨皯鐨勭嚎鏉� ctx.strokeStyle = 'rgba(70, 130, 180, 0.05)'; ctx.lineWidth = 0.5; - for (let y = 0; y < canvas.height; y += gridSize) { + // 闄嶄綆缃戞牸绾块鐜� + for (let y = 0; y < canvasHeight; y += gridSize * 1.5) { ctx.beginPath(); ctx.moveTo(0, y); - ctx.lineTo(canvas.width, y); + ctx.lineTo(canvasWidth, y); ctx.stroke(); - // 娣诲姞娉㈠姩鏁堟灉 + // 瀵规尝鍔ㄦ晥鏋滈噰鏍风巼闄嶄綆 ctx.beginPath(); - for (let x = 0; x < canvas.width; x += 5) { - const wave = Math.sin(x * 0.02 + time + y * 0.01) * 2; + for (let x = 0; x < canvasWidth; x += 10) { + const wave = Math.sin(x * 0.01 + time + y * 0.005) * 2; ctx.lineTo(x, y + wave); } ctx.strokeStyle = 'rgba(70, 130, 180, 0.02)'; ctx.stroke(); } - for (let x = 0; x < canvas.width; x += gridSize) { + for (let x = 0; x < canvasWidth; x += gridSize * 1.5) { ctx.beginPath(); ctx.moveTo(x, 0); - ctx.lineTo(x, canvas.height); + ctx.lineTo(x, canvasHeight); ctx.strokeStyle = 'rgba(70, 130, 180, 0.05)'; ctx.stroke(); } - // 娣诲姞闅忔満鍏夌偣 - for (let i = 0; i < 15; i++) { - const x = Math.random() * canvas.width; - const y = Math.random() * canvas.height; - const size = 2 + Math.sin(time * 2 + i) * 1; + // 鍑忓皯鍏夌偣鏁伴噺 + for (let i = 0; i < 10; i++) { + const x = Math.random() * canvasWidth; + const y = Math.random() * canvasHeight; + const size = 2 + Math.sin(time * 1.5 + i) * 1; const gradient = ctx.createRadialGradient(x, y, 0, x, y, size * 2); gradient.addColorStop(0, 'rgba(106, 219, 255, 0.2)'); @@ -277,16 +304,8 @@ // 缁樺埗鑺傜偣 const drawNodes = () => { - // 鑺傜偣閰嶇疆 - const nodes: Node[] = [ - { x: 0.15, y: 0.3, label: '閲囪喘', color: '#6ADBFF', icon: '馃摝' }, - { x: 0.35, y: 0.3, label: '鐢熶骇', color: '#5E72EB', icon: '馃彮' }, - { x: 0.65, y: 0.3, label: '閰嶉��', color: '#FF6A88', icon: '馃殮' }, - { x: 0.85, y: 0.3, label: '瀹㈡埛', color: '#FF9D6A', icon: '馃懃' }, - { x: 0.85, y: 0.6, label: '闇�姹傞娴�', color: '#FF6A88', icon: '馃搳' }, - { x: 0.5, y: 0.5, label: '鏅鸿兘鍒嗘瀽寮曟搸', color: '#5E72EB', isAI: true }, - ]; - + // 浣跨敤寮曠敤涓殑鑺傜偣鏁版嵁 + const nodes = nodesRef.current; const time = Date.now() * 0.001; nodes.forEach(node => { @@ -546,33 +565,53 @@ }); }; - // 鍒濆鍖栫矑瀛愮郴缁� + // 鍒濆鍖栫矑瀛� const initParticles = () => { - for (let i = 0; i < 40; i++) { + // 鍑忓皯鍒濆绮掑瓙鏁伴噺 + for (let i = 0; i < 20; i++) { setTimeout(() => createQuantumParticle(), i * 100); } }; - // 瀹氭湡娣诲姞鏂扮矑瀛� + // 瀹氭湡娣诲姞鏂扮矑瀛愶紝闄嶄綆棰戠巼 const particleInterval = setInterval(() => { - if (particles.length < 50) { + if (particles.length < 30) { createQuantumParticle(); } - }, 500); + }, 800); // 鍔ㄧ敾寰幆 - const animate = () => { + let lastTime = 0; + const targetFPS = 30; // 闄嶄綆鐩爣FPS浠ユ彁楂樻�ц兘 + const frameInterval = 1000 / targetFPS; + + const animate = (timestamp = 0) => { + const animationId = requestAnimationFrame(animate); + + // 闄愬埗甯х巼浠ユ彁楂樻�ц兘 + const deltaTime = timestamp - lastTime; + if (deltaTime < frameInterval) { + return animationId; + } + + // 璁板綍褰撳墠鏃堕棿 + lastTime = timestamp - (deltaTime % frameInterval); + + // 鏇存柊鍜岀粯鍒� updateParticles(); drawScene(); - requestAnimationFrame(animate); + + return animationId; }; initParticles(); - animate(); + const animationId = animate(); return () => { window.removeEventListener('resize', setCanvasSize); clearInterval(particleInterval); + // 娓呯悊鍔ㄧ敾甯� + cancelAnimationFrame(animationId); }; }, []); -- Gitblit v1.9.3