掘金创作者榜单投票的撒花效果是怎么做到的?带你用企业级封装实现

787 阅读5分钟

前言

最近在我司的工作中,摸鱼的时间愈发稀少。刚入职时,只需写几行代码,借助前辈们留下的“恩惠”,就能秒杀任务。而最近两周,开始参与更多的技术评审和完整的新需求,工作量陡然上升。同时,由于自己gap了一阵子没深度参与需求开发,缺乏规划,慢慢地“班味”又有些上来了。

所以在这里对平时对工作内容中涉及的一些技术方案做一些回顾,包括上一期的UI组件搭建之后也会同步。

使用 Canvas Confetti 实现炫酷的撒花效果

掘金最近有年度人气创作者榜单投票的活动,投票成功会有这么一个动画效果

image.png 刚好在我司也刚做了一个类似到需求,所以今天我们来讲一下使用Canvas Confetti 实现类似这样的撒花效果


Canvas Confetti 简介

是什么?

Canvas Confetti 是一个轻量级的 JavaScript 库,用于在网页中实现动态、炫酷的撒花动画效果。其基于 HTML5 Canvas API,提供了高性能和极其灵活的定制能力。

有什么特点?

  • 轻量高效:仅依赖 Canvas,库的体积非常小,性能表现优异。
  • 高度可定制:支持多种粒子样式、动画方向、颜色和数量。
  • 即插即用:只需几行代码即可实现基础撒花效果。
  • 响应式兼容:在 PC 和移动端都表现流畅。

用户故事

公司原本用了 vue-confetti-explosion这个经过Vue3封装的组件库,为了实现更丰富的效果以及更高的灵活性,于是采用了Canvas Confetti

官方资源


如何使用 Canvas Confetti 实现撒花效果

接下来,我们将通过一个完整的案例,从零开始实现撒花动画。包括从安装到定制效果,一步步拆解。


1. 安装库

如果项目使用的是现代化的构建工具(如 Vite、Webpack),可以通过 npm 安装 Canvas Confetti:

npm install canvas-confetti

如果直接在 HTML 中引入,也可以通过 CDN 使用:

<script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>

2. 基础撒花效果

以下是一个简单的撒花动画示例:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Canvas Confetti 示例</title>
  <style>
    body {
      display: flex;
      justify-content: center;
      align-items: center;
      height: 100vh;
      background-color: #f3f4f6;
    }
    button {
      padding: 12px 24px;
      font-size: 16px;
      cursor: pointer;
      border: none;
      border-radius: 4px;
      background-color: #4caf50;
      color: white;
    }
  </style>
</head>
<body>
  <button id="celebrateButton">撒花庆祝!</button>

  <script src="https://cdn.jsdelivr.net/npm/canvas-confetti@1.6.0/dist/confetti.browser.min.js"></script>
  <script>
    const button = document.getElementById('celebrateButton');

    button.addEventListener('click', () => {
      confetti({
        particleCount: 100,
        spread: 70, // 撒花的范围角度
        origin: { x: 0.5, y: 0.5 } // 动画起点(默认屏幕中心)
      });
    });
  </script>
</body>
</html>
效果说明
  • 点击按钮后,页面会从中心位置撒出 100 个粒子。
  • spread 属性控制粒子散开的角度范围,值越大效果越“爆炸”。

3. 自定义撒花样式

Canvas Confetti 提供了丰富的选项,我们可以通过定制颜色、方向、粒子形状等,创建更具个性化的撒花效果。

示例代码:
<script>
button.addEventListener('click', () => {
  confetti({
    particleCount: 200,
    angle: 90, // 撒花方向,90 表示垂直向上
    spread: 120, // 粒子扩散角度
    origin: { x: 0.5, y: 0.9 }, // 动画起点(屏幕底部中心)
    colors: ['#bb0000', '#ffffff'], // 自定义粒子颜色
    scalar: 1.2 // 粒子大小比例
  });
});
</script>
关键配置项
  • particleCount:粒子数量。
  • angle:撒花的方向角度。
  • colors:粒子的颜色列表。
  • scalar:粒子的缩放大小。

4. 连续撒花效果

如果需要在短时间内多次触发撒花动画,可以使用 setInterval 模拟:

<script>
button.addEventListener('click', () => {
  const duration = 3 * 1000; // 撒花持续时间(毫秒)
  const end = Date.now() + duration;

  (function frame() {
    confetti({
      particleCount: 5,
      startVelocity: 30,
      spread: 360,
      origin: {
        x: Math.random(),
        y: Math.random() - 0.2
      }
    });

    if (Date.now() < end) {
      requestAnimationFrame(frame);
    }
  })();
});
</script>
效果说明
  • 每次生成 5 个粒子,并从随机位置撒花。
  • 动画持续 3 秒,直到 end 时间结束。

5. 集成到 Vue 项目中

上面其实都是最基本的在h5和js中的使用,也用来过滤一部分读者,下面涉及在 Vue 项目中用Composable的思想将 Canvas Confetti 封装成一个全局的配置和方法,方便在多个组件中调用:

创建 confetti-animation.ts 配置文件:
import confetti from 'canvas-confetti';

class ConfettiAnimation {
  private interval: ReturnType<typeof setInterval> | null = null
  private animationEnd: number
  private duration: number
  private configs: ConfettiConfig[]
  private animationType: 'interval' | 'frame'

  constructor(options: ConfettiOptions) {
    this.duration = options.duration || 8 * 1000
    this.animationEnd = Date.now() + this.duration
    this.configs = options.configs.map(config => ({
      colors: config.colors,
      startVelocity: config.startVelocity || 50,
      spread: config.spread || 100,
      particleCount: config.particleCount || 45,
      scalar: config.scalar || 1.5,
      gravity: config.gravity || 0.5,
      ticks: config.ticks || 200,
      zIndex: 2001,
      ...config,
    }))
    this.animationType = options.animationType || 'interval'
  }

  start() {
    if (this.animationType === 'frame') {
      this.startFrameAnimation()
    } else {
      this.startIntervalAnimation()
    }
  }
  .....
  }

配置文件的核心就是传入你想要配置的options来自定义动画的效果,以及定时器和帧动画两种渲染方式

因为撒花庆祝要配置每一个confetti的位置等属性,所以要逐个配置

  this.configs.forEach(config => {
      confetti({
        ...config,
        colors: [...config.colors!],
        particleCount: config.particleCount,
        origin: { ...config.origin },
        })
      })
Composable文件配置
export const useConfettiAnimation = ({ autostart, configs, duration, animationType }: UseConfettiAnimationArgs) => {
  const confettiAnimation = createConfettiAnimation({ configs, duration, animationType })

  const start = () => confettiAnimation.start()
  const stop = () => confettiAnimation.stop()

  onMounted(() => {
    if (autostart) {
      start()
    }
  })

  onBeforeUnmount(() => {
    if (autostart) {
      stop()
    }
  })

  return { start, stop }

暴露出方法在页面组件中调用,结合具体的业务场景,一般都是支付和特定活动最后完成的反馈页的dialog中显示。

在 Vue 组件中使用:
<template>
  <div>
    <p >撒花庆祝反馈页面</p>
  </div>
</template>

<script lang="ts" setup>
import { ConfettiConfig } from 'utils/confetti-animation'
import { useConfettiAnimation } from '@/composables/confetti-animation'
  
const configs: ConfettiConfig[] = [
  {
    origin: { x: 0 },
    colors: [''''],
    angle: 60,
    particleCount: 2,
    spread: 55,
  },
  {
    origin: { x: 1 },
    colors: ['',''],
    angle: 120,
    particleCount: 2,
    spread: 55,
  },
]

const { stop } = useConfettiAnimation({ autostart: true, configs, animationType: 'frame' })
</script>

<style>
div {
  padding: 8px 16px;
  background-color: #007bff;
  color: white;
  border: none;
  border-radius: 4px;
  cursor: pointer;
}
</style>

示例预览

在这里插入图片描述 在这里插入图片描述

总结

通过 Canvas Confetti,我们可以轻松地在项目中添加炫酷的撒花动画效果。无论是表单提交成功后的提示,还是特殊节日的庆祝场景。之后对于工作流,自动化工具,我可能会做一些个人的分享,如果各位有更好的玩法或想法,欢迎在评论区交流分享!

完整源代码较长,可关注后联系作者获取(无套路,直接给)

微信公众号:冻柠葡萄呗