<template> <!-- 降雨效果canvas --> <div class="canvasRainPage"> <!-- 降雨 --> <canvas id="canvasRain"></canvas> <!-- 降雪 --> <canvas id="canvasSnow"></canvas> </div> </template> <script setup> const { proxy } = getCurrentInstance(); const timer = ref(null); const timerAll = ref(null); // 画笔 const ctx = ref(null); const ctxSnow = ref(null); // 画布的宽高 let w = window.innerWidth; let h = window.innerHeight; // 存放雨滴的数组 let arr = []; // 雨滴的数量 const size = ref(300); // 雨滴的构造函数 class Rain { x = random(w); y = random(h); ySpeed = random(2) + 8; show() { drawLine(this.x, this.y); } run() { if (this.y > h) { this.y = 0; this.x = random(w); } this.y = this.y + this.ySpeed; } } // 画线(雨滴) function drawLine(x1, y1) { ctx.value.beginPath(); ctx.value.strokeStyle = 'rgba(35, 195, 255, 1)'; ctx.value.moveTo(x1, y1); // 雨长度 ctx.value.lineTo(x1, y1 + 20); ctx.value.stroke(); } // 生成随机数 function random(num) { return Math.random() * num; } // 开始 function start() { for (let i = 0; i < size.value; i++) { let rain = new Rain(); arr.push(rain); rain.show(); } timer.value = setInterval(() => { ctx.value.clearRect(0, 0, w, h); for (let i = 0; i < size.value; i++) { arr[i].show(); arr[i].run(); } }, 30); } // 初始化 function init(ctx1) { ctx.value = ctx1; start(); } // 清除画布 function clearDraw() { ctx.value.clearRect(0, 0, w, h); } // 初始化 function initCanvas() { const canvas = document.querySelector('#canvasRain'); ctx.value = canvas.getContext('2d'); canvas.width = w; canvas.height = h; init(ctx.value); // 1-12个月的不同降雨量变化 let rainArr = [ { month: '1', rain: 300 }, { month: '2', rain: 350 }, { month: '3', rain: 400 }, { month: '4', rain: 450 }, { month: '5', rain: 550 }, { month: '6', rain: 600 }, { month: '7', rain: 1200 }, { month: '8', rain: 700 }, { month: '9', rain: 600 }, { month: '10', rain: 460 }, { month: '11', rain: 400 }, { month: '12', rain: 300 }, ]; let i = 0; timerAll.value = setInterval(() => { size.value = rainArr[i].rain; i++; if (i == 12) i = 0; init(ctx.value); //降雨效果 // 下雪效果 if (i >= 2 && i <= 10) { ctxSnow.value && ctxSnow.value.clearRect(0, 0, w, h); // 清除画布重新渲染 ctxSnow.value = null; } else { initSnow(); } }, 2083); } // 降雪效果 function initSnow() { const canvas2 = document.querySelector('#canvasSnow'); ctxSnow.value = canvas2.getContext('2d'); // 设置canvas画布大小 canvas2.width = w; canvas2.height = h; const config = { number: 300, // 生成的雪花数量 snowArr: [], pic: 'https://server1.wh-nf.cn:9000/newfiber-standard-kaifeng/2024/10/31/snow_20241031091359A072.png', // 雪花图片 }; let snowImg = new Image(); snowImg.src = config.pic; for (let i = 0; i < config.number; i++) { config.snowArr.push({ x: Math.random() * w, // 定义每片雪花的X轴 y: Math.random() * h, // Y轴 toX: Math.random(), // 雪花每一次渲染的X距离 toY: Math.random() * 1 + 5, //速度 size: Math.random() * 20 + 5, // 雪花的大小 }); } const dropAnimation = () => { if (!!!ctxSnow.value) return; ctxSnow.value.clearRect(0, 0, w, h); // 清除画布重新渲染 for (let i = 0; i < config.snowArr.length; i++) { let snow = config.snowArr[i]; // ctx.beginPath(); //绘制圆形雪花 后面直接图片代替 // ctx.arc(snow.x, snow.y, snow.size, 0, Math.PI * 2, true); // ctx.fillStyle = '#666'; // ctx.fill(); ctxSnow.value.drawImage(snowImg, snow.x, snow.y, snow.size, snow.size); snow.x = snow.x > w ? 0 : snow.x + snow.toX; // 每调一次函数向右移动一点 snow.y = snow.y > h ? 0 : snow.y + snow.toY; // 向下移动 } requestAnimationFrame(dropAnimation); }; requestAnimationFrame(dropAnimation); } onMounted(() => { initCanvas(); initSnow(); }); onBeforeUnmount(() => { if (timer.value) clearInterval(timer.value); if (timerAll.value) clearInterval(timerAll.value); clearDraw(); ctxSnow.value && ctxSnow.value.clearRect(0, 0, w, h); }); </script> <style lang="scss" scoped> .canvasRainPage { width: 100%; height: 100%; background: rgba(0, 59, 109, 0.2); position: absolute; left: 0px; top: 0px; z-index: 100; pointer-events: none; #canvasRain { position: absolute; left: 0px; top: 0px; z-index: 102; } #canvasSnow { position: absolute; left: 0px; top: 0px; z-index: 101; } } </style>