如何用React和Tailwind实现章鱼图标随鼠标指向随机移动
React + Tailwind CSS 实现随机移动且眼睛跟随鼠标的章鱼图标
实现思路
- 用React状态维护章鱼的当前位置和鼠标坐标
- 通过定时器周期性生成页面内的随机目标位置,让章鱼平滑移动过去
- 监听鼠标移动事件,计算章鱼与鼠标的相对角度,动态旋转章鱼眼睛指向鼠标
- 全程用Tailwind CSS处理定位、样式及过渡效果
完整组件代码
import { useState, useEffect, useRef } from 'react'; export default function Octopus() { // 章鱼当前位置 const [octopusPos, setOctopusPos] = useState({ x: 100, y: 100 }); // 鼠标位置 const [mousePos, setMousePos] = useState({ x: 0, y: 0 }); // 定时器引用 const moveIntervalRef = useRef(null); // 章鱼元素引用,用于获取尺寸 const octopusRef = useRef(null); // 监听鼠标移动 useEffect(() => { const handleMouseMove = (e) => { setMousePos({ x: e.clientX, y: e.clientY }); }; window.addEventListener('mousemove', handleMouseMove); return () => window.removeEventListener('mousemove', handleMouseMove); }, []); // 章鱼随机移动逻辑 useEffect(() => { const moveOctopus = () => { if (!octopusRef.current) return; // 获取页面可用范围(减去章鱼自身尺寸) const maxX = window.innerWidth - octopusRef.current.offsetWidth; const maxY = window.innerHeight - octopusRef.current.offsetHeight; // 生成随机目标位置 const targetX = Math.floor(Math.random() * maxX); const targetY = Math.floor(Math.random() * maxY); // 平滑移动到目标位置(每帧移动5px) const moveStep = () => { setOctopusPos(prev => { const dx = targetX - prev.x; const dy = targetY - prev.y; const distance = Math.sqrt(dx*dx + dy*dy); if (distance < 5) { return { x: targetX, y: targetY }; } return { x: prev.x + (dx / distance) * 5, y: prev.y + (dy / distance) * 5 }; }); }; // 每16ms执行一次移动(约60帧) const stepInterval = setInterval(moveStep, 16); // 到达目标后停止当前移动,3秒后生成下一个目标 setTimeout(() => { clearInterval(stepInterval); setTimeout(moveOctopus, 3000); }, 2000); }; // 初始化启动移动 moveIntervalRef.current = setTimeout(moveOctopus, 1000); return () => { if (moveIntervalRef.current) clearTimeout(moveIntervalRef.current); }; }, []); // 计算眼睛旋转角度 const getEyeRotation = () => { const dx = mousePos.x - octopusPos.x - 25; // 25是章鱼宽度的一半,调整眼睛旋转中心 const dy = mousePos.y - octopusPos.y - 25; const angle = Math.atan2(dy, dx) * (180 / Math.PI); return `rotate(${angle}deg)`; }; return ( <div ref={octopusRef} className="fixed w-16 h-16 transition-transform duration-100 ease-linear" style={{ left: `${octopusPos.x}px`, top: `${octopusPos.y}px` }} > {/* 章鱼主体(用SVG或图标替换,这里用圆形模拟) */} <div className="w-full h-full bg-blue-500 rounded-full relative"> {/* 章鱼眼睛 */} <div className="absolute w-4 h-4 bg-white rounded-full top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2"> <div className="absolute w-2 h-2 bg-black rounded-full top-1/2 left-1/2 -translate-y-1/2" style={{ transform: getEyeRotation, transformOrigin: 'center center' }} ></div> </div> </div> </div> ); }
关键细节说明
- 随机移动:通过定时器生成目标位置,用逐帧移动实现平滑过渡,避免瞬移的生硬感;每次到达目标后停顿3秒再生成下一个位置
- 眼睛跟随:利用
Math.atan2计算鼠标与章鱼中心的夹角,将角度转换为CSS旋转值,通过Tailwind的transform实现旋转 - Tailwind样式:用
fixed定位章鱼,transition-transform实现移动平滑过渡,relative/absolute定位眼睛 - 边界处理:计算目标位置时减去章鱼自身尺寸,避免章鱼移出可视区域
使用说明
- 将上述组件导入到你的React项目中
- 替换章鱼主体的模拟圆形为你实际的章鱼图标(可以用SVG或图片,调整
w-16 h-16等尺寸类适配) - 根据图标实际的眼睛位置,调整
getEyeRotation中的偏移值(示例中的25是基于w-16的一半)
内容的提问来源于stack exchange,提问作者Numan Talukder
相关产品推荐
相关产品推荐

