ReactJS中实现图片叠加鼠标追踪数据及跨窗口传图问题
解决方案
一、在原页面叠加鼠标追踪信息
直接用React的ref和事件监听解决图片位置获取问题,通过canvas叠加在图片上方绘制轨迹:
- 使用
useRef获取图片和canvas元素,替代原生DOM查询 - 监听图片
load事件确保加载完成,同时监听页面scroll事件实时更新图片位置 - 用相对定位容器包裹图片和canvas,让canvas绝对定位在图片上方
import { useRef, useEffect, useState } from 'react'; function SketchReplay({ imgSrc, mouseTracks, originalCanvasWidth, originalCanvasHeight }) { const imgRef = useRef(null); const canvasRef = useRef(null); const [imgScale, setImgScale] = useState({ x: 1, y: 1 }); useEffect(() => { const updateCanvas = () => { if (!imgRef.current) return; // 获取图片实际显示尺寸 const displayWidth = imgRef.current.offsetWidth; const displayHeight = imgRef.current.offsetHeight; // 计算缩放比例(原始画布尺寸 → 当前显示尺寸) setImgScale({ x: displayWidth / originalCanvasWidth, y: displayHeight / originalCanvasHeight }); drawTracks(); }; const drawTracks = () => { if (!canvasRef.current || !imgScale.x) return; const ctx = canvasRef.current.getContext('2d'); const { width, height } = imgRef.current; canvasRef.current.width = width; canvasRef.current.height = height; ctx.clearRect(0, 0, width, height); // 绘制鼠标轨迹 ctx.strokeStyle = '#ff0000'; ctx.lineWidth = 2; ctx.beginPath(); mouseTracks.forEach((point, idx) => { const x = point.x * imgScale.x; const y = point.y * imgScale.y; idx === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); }); ctx.stroke(); }; // 绑定事件 imgRef.current?.addEventListener('load', updateCanvas); window.addEventListener('scroll', updateCanvas); window.addEventListener('resize', updateCanvas); updateCanvas(); // 清理事件 return () => { imgRef.current?.removeEventListener('load', updateCanvas); window.removeEventListener('scroll', updateCanvas); window.removeEventListener('resize', updateCanvas); }; }, [mouseTracks, originalCanvasWidth, originalCanvasHeight]); return ( <div style={{ position: 'relative', display: 'inline-block' }}> <img ref={imgRef} src={imgSrc} alt="Sketchpad screenshot" style={{ maxWidth: '100%', display: 'block' }} /> <canvas ref={canvasRef} style={{ position: 'absolute', top: 0, left: 0, pointerEvents: 'none' // 不遮挡图片点击事件 }} /> </div> ); }
二、在新窗口打开并叠加数据
通过window.open创建新窗口,直接在新窗口中动态生成图片和canvas,传递轨迹数据进行绘制:
方案1:直接在新窗口创建DOM
function SketchViewer({ imgSrc, mouseTracks, originalCanvasWidth, originalCanvasHeight }) { const openReplayWindow = () => { const newWindow = window.open('', '_blank', 'width=800,height=600'); if (!newWindow) return; newWindow.onload = () => { // 创建容器 const container = newWindow.document.createElement('div'); container.style.position = 'relative'; newWindow.document.body.style.margin = '0'; newWindow.document.body.appendChild(container); // 创建图片 const img = newWindow.document.createElement('img'); img.src = imgSrc; img.style.maxWidth = '100%'; img.style.display = 'block'; container.appendChild(img); // 创建canvas const canvas = newWindow.document.createElement('canvas'); canvas.style.position = 'absolute'; canvas.style.top = '0'; canvas.style.left = '0'; canvas.style.pointerEvents = 'none'; container.appendChild(canvas); // 图片加载完成后绘制轨迹 img.onload = () => { const scaleX = img.width / originalCanvasWidth; const scaleY = img.height / originalCanvasHeight; canvas.width = img.width; canvas.height = img.height; const ctx = canvas.getContext('2d'); ctx.strokeStyle = '#ff0000'; ctx.lineWidth = 2; ctx.beginPath(); mouseTracks.forEach((point, idx) => { const x = point.x * scaleX; const y = point.y * scaleY; idx === 0 ? ctx.moveTo(x, y) : ctx.lineTo(x, y); }); ctx.stroke(); }; }; }; return ( <img src={imgSrc} alt="Sketchpad screenshot" onClick={openReplayWindow} style={{ cursor: 'pointer', maxWidth: '100%' }} /> ); }
方案2:用localStorage传递大数据(适合图片是base64或大文件的情况)
// 主页面点击事件 const openReplayWindow = () => { // 临时存储数据 localStorage.setItem('sketchImg', imgSrc); localStorage.setItem('sketchTracks', JSON.stringify(mouseTracks)); localStorage.setItem('sketchSize', JSON.stringify({ width: originalCanvasWidth, height: originalCanvasHeight })); // 打开专门的回放页面 window.open('/sketch-replay.html', '_blank'); };
在sketch-replay.html中读取数据并绘制:
<!DOCTYPE html> <html> <body> <script> window.onload = () => { // 读取数据 const imgSrc = localStorage.getItem('sketchImg'); const tracks = JSON.parse(localStorage.getItem('sketchTracks')); const { width: originalWidth, height: originalHeight } = JSON.parse(localStorage.getItem('sketchSize')); // 绘制逻辑和方案1一致,创建img、canvas并绘制轨迹 // 清理临时数据 localStorage.removeItem('sketchImg'); localStorage.removeItem('sketchTracks'); localStorage.removeItem('sketchSize'); }; </script> </body> </html>
内容的提问来源于stack exchange,提问作者jason
相关产品推荐
相关产品推荐

