前言

好久好久没写博客了,人一旦停止记录,就会感觉学习没有积累。虽然相应的有更多时间去coding,不过记录一下才更不容易忘记。

展示效果

起因

其实对particle熟悉的话,就知道这个和他基本上是一样的效果,为什么不直接用particle呢?首先是因为nuxt3开发不知道怎么使用这个插件,只好网上cv一个然后改成对应的vue代码,不过改代码也是一件慢慢进步的事情。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
<template>
<canvas ref="canvas" id="canvas" :width="state.width" :height="state.height"></canvas>
</template>

<script lang="ts" setup>
// 获取dom
const canvas = ref(null);
interface stateInit {
width: number,
height: number
}
const state = reactive<stateInit>({
width: 500,
height: 500,
})
const ctx = ref(null);
onMounted(() => {
ctx.value = canvas.value.getContext('2d');
setCanvasSize();
window.onresize = () => {
setCanvasSize();
}
raf();
})
const colors = reactive(['#ed1941', '#f05b72', '#ef4136', '#f15a22', '#8e3e1f', '#fcaf17', '#b76f40', '#00ae9d', '#009ad6', '#1d953f', '#426ab3', '#6950a1', '#74787c', '#2a5caa']);
// 设置canvas宽高
const setCanvasSize = (): void => {
state.width = window.innerWidth;
state.height = window.innerHeight - 40;
}
/**
* 获取min(包含) - max(不包含)之间的随机数
* @param {number} min 最小值
* @param {number} max 最大值
* @returns
*/
const getRandom = (min: number, max: number): number => {
return Math.random() * (max - min) + min;
}
/**
* 获取两点距离
* @param {object} a 第一个点的位置
* @param {object} b 第二个点的位置
* @returns
*/
interface pos {
x: number,
y: number
}
const getDistance = (a: pos, b: pos): number => {
const x = a.x - b.x;
const y = a.y - b.y;
return Math.hypot(x, y); // Math.sqrt(x * x + y * y);
}
// 创建粒子函数
interface particle {
radius: number,
x: number,
y: number,
speedX: number,
speedY: number,
color: string
}
const create = (): particle => {
// 粒子半径
let radius = getRandom(2.2, 4);
// 粒子位置
let x = getRandom(0 + radius, state.width - radius);
let y = getRandom(0 + radius, state.height - radius);
// 粒子运动速度
let speedX = getRandom(-1, 1);
let speedY = getRandom(-1, 1);
// 粒子颜色
let color = colors[Math.floor(getRandom(0, colors.length))];
return {
radius,
x,
y,
speedX,
speedY,
color
}
}
// 绘制粒子函数
const draw = (particle: particle): void => {
// const ctx = canvas.value.getContext('2d');
ctx.value.beginPath();
ctx.value.fillStyle = particle.color;
ctx.value.arc(particle.x, particle.y, particle.radius, 0, 2 * Math.PI);
ctx.value.fill();
}
// 连线粒子函数
const link = (particle: particle): void => {
// const ctx = canvas.value.getContext('2d');
for (const p of particles) {
const distance = getDistance(particle, p);
if (distance < 150) {
ctx.value.beginPath();
ctx.value.lineWidth = 0.1;
ctx.value.strokeStyle = particle.color;
ctx.value.moveTo(particle.x, particle.y);
ctx.value.lineTo(p.x, p.y);
ctx.value.stroke();
}
}
}
// 移动粒子函数
const move = (particle: particle): void => {
// 碰撞边界后反弹
if (particle.x <= particle.radius || particle.x + particle.radius >= state.width) {
particle.speedX *= -1;
}
if (particle.y <= particle.radius || particle.y + particle.radius >= state.height) {
particle.speedY *= -1;
}
particle.x += particle.speedX;
particle.y += particle.speedY;
}
// 粒子数组
const particles: particle[] = [];
for (let i = 0; i < 88; i++) {
let particle = create();
particles.push(particle);
}
// 动画
const raf = (): void => {
step()
// window.requestAnimationFrame(step);
}
const step = (): void => {
// const ctx = canvas.value.getContext('2d');
// 清空画布
ctx.value.clearRect(0, 0, state.width, state.height);
// 更新粒子
for (const particle of particles) {
move(particle);
draw(particle);
link(particle);
}
window.requestAnimationFrame(step);
}
</script>

<style lang="scss" scoped>
* {
margin: 0;
padding: 0;
}

canvas {
display: block;
}

</style>