vue3 + canvas 弄一个烟花效果

创建一个简单的烟花效果需要使用 Vue 3 和 Canvas。下面代码与展示效果

<template>
  <div class="wrz_blog-fireworks-container">
    <canvas ref="fireworksCanvas" width="1000" height="1000"></canvas>
  </div>
</template>

<script setup>
import { ref, onMounted,watch} from 'vue';

const fireworksCanvas = ref(null);


onMounted(() => {
  const canvas = fireworksCanvas.value;
  const ctx = canvas.getContext("2d");

  // 获取实际显示的宽度和高度
  const displayWidth = canvas.clientWidth;
  const displayHeight = canvas.clientHeight;

  // 设置Canvas元素的实际宽度和高度
  canvas.width = displayWidth;
  canvas.height = displayHeight;

  // 缩放Canvas上下文以适应实际显示尺寸
  ctx.scale(displayWidth / canvas.width, displayHeight / canvas.height);

  const fireworks = [];


  class Particle {
    constructor(x, y, color, velocity, isExplosion = false) {
      this.x = x;
      this.y = y;
      this.color = color;
      this.velocity = velocity;
      this.radius = isExplosion ? 5 : 1; // 调整点的大小
      this.alpha = 1;
      this.isExplosion = isExplosion;
    }

    draw() {
      ctx.globalAlpha = this.alpha;
      ctx.beginPath();
      if (this.isExplosion) {
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
      } else {
        ctx.moveTo(this.x, this.y);
        ctx.lineTo(this.x + this.velocity.x * 5, this.y + this.velocity.y * 5);
        ctx.strokeStyle = this.color;
        ctx.stroke();
      }
      ctx.fillStyle = this.color;
      ctx.fill();
      ctx.globalAlpha = 1;
    }

    update() {
      if (this.isExplosion) {
        this.x += this.velocity.x;
        this.y += this.velocity.y;
        this.radius -= 0.1; // 调整点的变小速度
      } else {
        this.x += this.velocity.x;
        this.y += this.velocity.y;
        this.alpha -= 0.02;
      }
    }
  }

  function createFirework() {
    const x = Math.random() * canvas.width;
    const y = canvas.height;
    const color = getRandomColor();
    const velocity = {
      x: Math.random() * 3 - 1.5,
      y: -Math.random() * 6 - 2,
    };

    const firework = new Particle(x, y, color, velocity);
    fireworks.push(firework);

    // 调整初始线的粗细和颜色
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x + velocity.x * 5, y + velocity.y * 5);
    ctx.strokeStyle = color;
    ctx.lineWidth = 2; // 调整线的粗细
    ctx.stroke();
  }

  function createExplosion(x, y, color) {
    const particles = [];
    const numParticles = Math.random() * 20 + 10;
    for (let i = 0; i < numParticles; i++) {
      const angle = (Math.PI / 15) * i;
      const velocity = {
        x: Math.cos(angle) * (Math.random() * 5 + 2),
        y: Math.sin(angle) * (Math.random() * 5 + 2),
      };
      const isExplosion = Math.random() > 0.5;
      const particleColor = isExplosion ? color : getRandomColor();
      const particle = new Particle(x, y, particleColor, velocity, isExplosion);
      particles.push(particle);
    }
    fireworks.push(particles);
  }

  function getRandomColor() {
    const colors = [
      "#ff0000", "#00ff00", "#0000ff", "#ffff00", "#ff00ff", "#ffa500", "#800080",
      "#ff6666", "#66ff66", "#6666ff", "#ffff66", "#ff66ff"
    ];
    return colors[Math.floor(Math.random() * colors.length)];
  }


  function animate() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    if (Math.random() < 0.03) {
      createFirework();
    }

    for (let i = 0; i < fireworks.length; i++) {
      const firework = fireworks[i];

      if (firework instanceof Particle) {
        firework.draw();
        firework.update();

        if (firework.alpha <= 0 || firework.radius <= 0) {
          const { x, y, color } = firework;
          fireworks.splice(i, 1);
          createExplosion(x, y, color);
        }
      } else if (Array.isArray(firework)) {
        for (let j = 0; j < firework.length; j++) {
          const particle = firework[j];
          particle.draw();
          particle.update();
        }

        if (firework.length > 0 && (firework[0].alpha <= 0 || firework[0].radius <= 0)) {
          fireworks.splice(i, 1);
          i--;
        }
      }
    }

    requestAnimationFrame(animate);
  }

  animate();
});


</script>


.wrz_blog-fireworks-container {
    position: fixed;
    bottom: 0;
    left: 0;
    top: -200px;
    height: 100%;
    width: 100%;
    z-index: 0;
    pointer-events: none;
    display: flex;
    justify-content: center;
    align-items: center;
}

.wrz_blog-fireworks-container canvas {
    height: 100%;
    width: 100%;
    display: block;
}

将以上代码直接弄成一个组件 之后再需要的位置引入

  
   import Fireworks from '@/components/fireworks/Fireworks';

	<template>
 	    <Fireworks />
    </template>
    

查看效果

访问王润泽博客 查看
https://wangrunze.com/

### 如何在 Vue3 中使用 Canvas 实现礼花特效 #### 创建 Vue 组件并引入 Canvas 为了实现在 Vue3 项目中的 Canvas 礼花特效,可以创建一个新的组件 `Fireworks.vue` 来专门处理这个功能。在这个组件里,通过 `<canvas>` 元素来绘制动效果。 ```html <template> <div class="firework-container"> <canvas ref="fireworkCanvas"></canvas> </div> </template> <script setup> import { onMounted, ref } from &#39;vue&#39; const fireworkCanvas = ref(null) onMounted(() => { const canvas = fireworkCanvas.value const ctx = canvas.getContext(&#39;2d&#39;) // 设置布大小跟随窗口变化 function resizeCanvas() { canvas.width = window.innerWidth canvas.height = window.innerHeight } window.addEventListener(&#39;resize&#39;, resizeCanvas) resizeCanvas() // 定义烟花类和其他逻辑... }) </script> <style scoped> .firework-container { position: absolute; top: 0; left: 0; z-index: -1; /* 确保不会覆盖其他页面元素 */ } </style> ``` #### 编写烟花粒子系统的核心算法 接下来,在上述脚本部分继续定义烟花爆炸的效果模拟函数: ```javascript class Particle { constructor(x, y) { this.x = x this.y = y this.color = getRandomColor() this.size = Math.random() * 5 + 2 this.velocityX = (Math.random() - 0.5) * 10 this.velocityY = (Math.random() - 0.5) * 10 this.gravity = 0.1 this.friction = 0.97 } update() { this.velocityY += this.gravity this.x += this.velocityX this.y += this.velocityY this.velocityX *= this.friction this.velocityY *= this.friction } draw(ctx) { ctx.fillStyle = this.color ctx.beginPath() ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2) ctx.fill() } } function createExplosion(x, y) { let particles = [] for(let i=0;i<100;i++){ particles.push(new Particle(x,y)) } return particles } // 颜色随机生成辅助方法 function getRandomColor() { const colors = [&#39;#ff6b6b&#39;,&#39;#feca57&#39;,&#39;#4ecdc4&#39;,&#39;#aabbcc&#39;] return colors[Math.floor(Math.random()*colors.length)] } ``` 这部分代码实现了基本的粒子物理行为以及颜色的选择机制[^1]。 #### 动态渲染与事件触发 为了让用户交互能够触发展示烟花效果,可以在鼠标点击或移动时调用 `createExplosion()` 函数,并将产生的粒子加入到全局数组中定期更新它们的位置和状态。 ```javascript let allParticles = [] function animate() { requestAnimationFrame(animate) ctx.clearRect(0, 0, canvas.width, canvas.height) if(allParticles.length > 0){ allParticles.forEach((particle,index)=>{ particle.update() particle.draw(ctx) // 当粒子变得太小时移除它 if(particle.size<=0.5 || !isParticleVisible(particle)){ allParticles.splice(index,1) } }) } } canvas.addEventListener(&#39;click&#39;,(event)=>{ const mouseX=event.clientX, mouseY=event.clientY allParticles=[...allParticles,...createExplosion(mouseX,mouseY)] }) animate() ``` 这段代码展示了如何监听用户的点击动作并在指定位置产生活动的烟花效果
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值