<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://www.deanhan.cn/wp-content/uploads/2017/12/snow.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>