React Typescript实现HTML5 Canvas星空穿梭动画报错如何解决
React + TypeScript 星空穿梭动画修复方案
以下是可直接运行的修复后代码:
import React, { useRef, useEffect } from 'react'; const Canvas = () => { const canvasRef = useRef<HTMLCanvasElement | null>(null); useEffect(() => { const canvas = canvasRef.current; if (!canvas) return; const ctx = canvas.getContext('2d'); if (!ctx) return; // 获取URL参数工具函数 const getUrlParameter = (sParam: string) => { const sPageURL = decodeURIComponent(window.location.search.substring(1)); const sURLVariables = sPageURL.split('&'); for (let i = 0; i < sURLVariables.length; i++) { const sParameterName = sURLVariables[i].split('='); if (sParameterName[0] === sParam) { return sParameterName[1] === undefined ? true : sParameterName[1]; } } return null; }; // 定义Star类 class Star { X: number; Y: number; SX: number; SY: number; W: number; H: number; age: number; dies: number; ID: number; C: string; constructor() { this.X = canvas.width / 2; this.Y = canvas.height / 2; this.SX = Math.random() * 10 - 5; this.SY = Math.random() * 10 - 5; const start = Math.max(canvas.width, canvas.height); this.X += this.SX * start / 10; this.Y += this.SY * start / 10; this.W = 1; this.H = 1; this.age = 0; this.dies = 500; starIndex++; stars[starIndex] = this; this.ID = starIndex; this.C = "#ffffff"; } Draw() { this.X += this.SX; this.Y += this.SY; this.SX += this.SX / (50 / acceleration); this.SY += this.SY / (50 / acceleration); this.age++; if ( this.age == Math.floor(50 / acceleration) || this.age == Math.floor(150 / acceleration) || this.age == Math.floor(300 / acceleration) ) { this.W++; this.H++; } if ( this.X + this.W < 0 || this.X > canvas.width || this.Y + this.H < 0 || this.Y > canvas.height ) { delete stars[this.ID]; numStars--; } ctx.fillStyle = this.C; ctx.fillRect(this.X, this.Y, this.W, this.H); } } const stars: Record<number, Star> = {}; let starIndex = 0; let numStars = 0; let acceleration: number = 1; let starsToDraw: number = (canvas.width * canvas.height) / 200; // 处理URL参数,转成数字类型 const customStars = getUrlParameter("stars"); if (customStars) starsToDraw = Number(customStars); const customAccel = getUrlParameter("accel"); if (customAccel) acceleration = Number(customAccel); // 初始化画布尺寸 canvas.width = window.innerWidth; canvas.height = window.innerHeight; const draw = () => { // 同步窗口尺寸 if (canvas.width !== window.innerWidth) canvas.width = window.innerWidth; if (canvas.height !== window.innerHeight) canvas.height = window.innerHeight; // 绘制背景蒙层 ctx.fillStyle = "rgba(0, 0, 0, 0.8)"; ctx.fillRect(0, 0, canvas.width, canvas.height); // 补充缺失的星星 for (let i = numStars; i < starsToDraw; i++) { new Star(); numStars++; } // 绘制所有星星 for (const starId in stars) { stars[starId].Draw(); } }; // 启动定时器,存储id用于清理 const intervalId = setInterval(draw, 40); // 组件卸载时清理定时器 return () => clearInterval(intervalId); }, []); return <canvas ref={canvasRef} style={{ position: 'fixed', top: 0, left: 0, width: '100vw', height: '100vh', zIndex: -1 }} />; } export default Canvas;
核心修改点
- 替换传统函数构造的Star为TS Class,显式定义每个属性的类型,解决构造函数this指向和类型识别的报错
- 新增canvas实例和context的非空判断,跳过空值执行分支,消除类型报错同时避免运行时异常
- 对URL参数获取的自定义配置做强制数值转换,避免字符串类型参与数值运算导致的逻辑错误
- 补充定时器清理逻辑,组件卸载时自动清除动画定时器,避免内存泄漏和重复执行问题
- 给canvas元素补充全屏固定定位样式,确保动画默认占满整个浏览器视口,无需额外父容器适配
内容的提问来源于stack exchange,提问作者Rushikesh Gadekar
相关产品推荐
相关产品推荐

