|
|
@@ -1,257 +0,0 @@
|
|
|
-<template>
|
|
|
- <canvas ref="waveCanvas" class="wave-canvas"></canvas>
|
|
|
-</template>
|
|
|
-
|
|
|
-<script>
|
|
|
-export default {
|
|
|
- name: "WaveCanvas",
|
|
|
- data() {
|
|
|
- return {
|
|
|
- canvas: null,
|
|
|
- ctx: null,
|
|
|
- animationId: null,
|
|
|
- time: 0,
|
|
|
- waves: [],
|
|
|
- particles: []
|
|
|
- };
|
|
|
- },
|
|
|
- mounted() {
|
|
|
- this.initCanvas();
|
|
|
- this.initWaves();
|
|
|
- this.initParticles();
|
|
|
- this.animate();
|
|
|
- window.addEventListener("resize", this.handleResize);
|
|
|
- },
|
|
|
- beforeDestroy() {
|
|
|
- if (this.animationId) {
|
|
|
- cancelAnimationFrame(this.animationId);
|
|
|
- }
|
|
|
- window.removeEventListener("resize", this.handleResize);
|
|
|
- },
|
|
|
- methods: {
|
|
|
- initCanvas() {
|
|
|
- this.canvas = this.$refs.waveCanvas;
|
|
|
- this.ctx = this.canvas.getContext("2d");
|
|
|
- this.setCanvasSize();
|
|
|
- },
|
|
|
- setCanvasSize() {
|
|
|
- const parent = this.canvas.parentElement;
|
|
|
- this.canvas.width = parent.clientWidth;
|
|
|
- this.canvas.height = parent.clientHeight;
|
|
|
- },
|
|
|
- handleResize() {
|
|
|
- this.setCanvasSize();
|
|
|
- this.initParticles();
|
|
|
- },
|
|
|
- initWaves() {
|
|
|
- // 创建多层波浪参数
|
|
|
- this.waves = [
|
|
|
- {
|
|
|
- amplitude: 30,
|
|
|
- frequency: 0.01,
|
|
|
- speed: 0.02,
|
|
|
- yOffset: 0.7,
|
|
|
- color: "rgba(64, 156, 255, 0.4)",
|
|
|
- lineWidth: 2
|
|
|
- },
|
|
|
- {
|
|
|
- amplitude: 25,
|
|
|
- frequency: 0.015,
|
|
|
- speed: 0.025,
|
|
|
- yOffset: 0.75,
|
|
|
- color: "rgba(100, 181, 246, 0.3)",
|
|
|
- lineWidth: 1.5
|
|
|
- },
|
|
|
- {
|
|
|
- amplitude: 20,
|
|
|
- frequency: 0.008,
|
|
|
- speed: 0.015,
|
|
|
- yOffset: 0.8,
|
|
|
- color: "rgba(144, 202, 249, 0.25)",
|
|
|
- lineWidth: 1
|
|
|
- },
|
|
|
- {
|
|
|
- amplitude: 35,
|
|
|
- frequency: 0.012,
|
|
|
- speed: 0.018,
|
|
|
- yOffset: 0.65,
|
|
|
- color: "rgba(64, 156, 255, 0.2)",
|
|
|
- lineWidth: 1.5
|
|
|
- }
|
|
|
- ];
|
|
|
- },
|
|
|
- initParticles() {
|
|
|
- this.particles = [];
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
-
|
|
|
- // 创建点阵粒子
|
|
|
- const cols = Math.floor(width / 15);
|
|
|
- const rows = Math.floor(height / 15);
|
|
|
-
|
|
|
- for (let i = 0; i < cols; i++) {
|
|
|
- for (let j = 0; j < rows; j++) {
|
|
|
- if (Math.random() > 0.6) {
|
|
|
- this.particles.push({
|
|
|
- x: i * 15 + Math.random() * 10,
|
|
|
- y: j * 15 + Math.random() * 10,
|
|
|
- baseY: j * 15,
|
|
|
- size: Math.random() * 1.5 + 0.5,
|
|
|
- opacity: Math.random() * 0.5 + 0.2,
|
|
|
- speed: Math.random() * 0.5 + 0.2,
|
|
|
- phase: Math.random() * Math.PI * 2
|
|
|
- });
|
|
|
- }
|
|
|
- }
|
|
|
- }
|
|
|
- },
|
|
|
- drawWave(wave, index) {
|
|
|
- const ctx = this.ctx;
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
- const baseY = height * wave.yOffset;
|
|
|
-
|
|
|
- ctx.beginPath();
|
|
|
- ctx.strokeStyle = wave.color;
|
|
|
- ctx.lineWidth = wave.lineWidth;
|
|
|
-
|
|
|
- // 绘制波浪线
|
|
|
- for (let x = 0; x <= width; x += 2) {
|
|
|
- const y = baseY +
|
|
|
- Math.sin(x * wave.frequency + this.time * wave.speed + index) * wave.amplitude +
|
|
|
- Math.sin(x * wave.frequency * 2 + this.time * wave.speed * 1.5) * (wave.amplitude * 0.5);
|
|
|
-
|
|
|
- if (x === 0) {
|
|
|
- ctx.moveTo(x, y);
|
|
|
- } else {
|
|
|
- ctx.lineTo(x, y);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- ctx.stroke();
|
|
|
-
|
|
|
- // 填充波浪下方渐变
|
|
|
- ctx.lineTo(width, height);
|
|
|
- ctx.lineTo(0, height);
|
|
|
- ctx.closePath();
|
|
|
-
|
|
|
- const gradient = ctx.createLinearGradient(0, baseY - wave.amplitude, 0, height);
|
|
|
- gradient.addColorStop(0, wave.color.replace(/[\d.]+\)$/, "0.1)"));
|
|
|
- gradient.addColorStop(0.5, wave.color.replace(/[\d.]+\)$/, "0.05)"));
|
|
|
- gradient.addColorStop(1, "transparent");
|
|
|
-
|
|
|
- ctx.fillStyle = gradient;
|
|
|
- ctx.fill();
|
|
|
- },
|
|
|
- drawParticles() {
|
|
|
- const ctx = this.ctx;
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
-
|
|
|
- this.particles.forEach(particle => {
|
|
|
- // 粒子随波浪波动
|
|
|
- const waveY = Math.sin(particle.x * 0.01 + this.time * 0.02) * 20 +
|
|
|
- Math.sin(particle.x * 0.02 + this.time * 0.03) * 10;
|
|
|
-
|
|
|
- const y = particle.baseY + waveY * particle.speed;
|
|
|
-
|
|
|
- // 只在底部区域显示粒子
|
|
|
- if (y > height * 0.5) {
|
|
|
- const opacity = particle.opacity * (1 - (y - height * 0.5) / (height * 0.5));
|
|
|
-
|
|
|
- ctx.beginPath();
|
|
|
- ctx.arc(particle.x, y, particle.size, 0, Math.PI * 2);
|
|
|
- ctx.fillStyle = `rgba(100, 200, 255, ${Math.max(0, opacity)})`;
|
|
|
- ctx.fill();
|
|
|
-
|
|
|
- // 添加发光效果
|
|
|
- if (opacity > 0.3) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.arc(particle.x, y, particle.size * 3, 0, Math.PI * 2);
|
|
|
- ctx.fillStyle = `rgba(100, 200, 255, ${opacity * 0.2})`;
|
|
|
- ctx.fill();
|
|
|
- }
|
|
|
- }
|
|
|
- });
|
|
|
- },
|
|
|
- drawGrid() {
|
|
|
- const ctx = this.ctx;
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
-
|
|
|
- // 绘制淡淡的网格线
|
|
|
- ctx.strokeStyle = "rgba(64, 156, 255, 0.03)";
|
|
|
- ctx.lineWidth = 0.5;
|
|
|
-
|
|
|
- const gridSize = 30;
|
|
|
-
|
|
|
- for (let x = 0; x <= width; x += gridSize) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(x, height * 0.5);
|
|
|
- ctx.lineTo(x, height);
|
|
|
- ctx.stroke();
|
|
|
- }
|
|
|
-
|
|
|
- for (let y = Math.floor(height * 0.5); y <= height; y += gridSize) {
|
|
|
- ctx.beginPath();
|
|
|
- ctx.moveTo(0, y);
|
|
|
- ctx.lineTo(width, y);
|
|
|
- ctx.stroke();
|
|
|
- }
|
|
|
- },
|
|
|
- drawGlow() {
|
|
|
- const ctx = this.ctx;
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
-
|
|
|
- // 底部发光效果
|
|
|
- const gradient = ctx.createLinearGradient(0, height - 150, 0, height);
|
|
|
- gradient.addColorStop(0, "transparent");
|
|
|
- gradient.addColorStop(0.5, "rgba(64, 156, 255, 0.1)");
|
|
|
- gradient.addColorStop(1, "rgba(64, 156, 255, 0.25)");
|
|
|
-
|
|
|
- ctx.fillStyle = gradient;
|
|
|
- ctx.fillRect(0, height - 150, width, 150);
|
|
|
- },
|
|
|
- animate() {
|
|
|
- const ctx = this.ctx;
|
|
|
- const width = this.canvas.width;
|
|
|
- const height = this.canvas.height;
|
|
|
-
|
|
|
- // 清空画布
|
|
|
- ctx.clearRect(0, 0, width, height);
|
|
|
-
|
|
|
- // 绘制网格
|
|
|
- this.drawGrid();
|
|
|
-
|
|
|
- // 绘制波浪
|
|
|
- this.waves.forEach((wave, index) => {
|
|
|
- this.drawWave(wave, index);
|
|
|
- });
|
|
|
-
|
|
|
- // 绘制粒子
|
|
|
- this.drawParticles();
|
|
|
-
|
|
|
- // 绘制发光效果
|
|
|
- this.drawGlow();
|
|
|
-
|
|
|
- // 更新时间
|
|
|
- this.time += 1;
|
|
|
-
|
|
|
- // 继续动画
|
|
|
- this.animationId = requestAnimationFrame(this.animate.bind(this));
|
|
|
- }
|
|
|
- }
|
|
|
-};
|
|
|
-</script>
|
|
|
-
|
|
|
-<style scoped>
|
|
|
-.wave-canvas {
|
|
|
- position: absolute;
|
|
|
- bottom: 0;
|
|
|
- left: 0;
|
|
|
- width: 100%;
|
|
|
- height: 100%;
|
|
|
- pointer-events: none;
|
|
|
-}
|
|
|
-</style>
|