实现一个炫酷的 DOM 转粒子动画

前言

在我网络冲浪的时候,无意之间看到了一位大佬做的粒子效果很是炫酷,不过只做了 Mac 端的示例,我于是就学习做了一个 Web 端的 DOM 转 Canvas 粒子动画效果。代码仓库、说明文档及NPM包都在结尾。

实现思路

实现思路的话十分好理解,一句话就可以说的清。

先用 html2canvas 将 DOM 转成 canvas ,然后将 canvas 转成粒子开始做动画。

全部实现下来核心代码 200 多行,7kb左右吧。不过由于依赖了 html2canvas,打包后还是有 200+ kb 的大小。

开发逻辑

输入

既然是要将 DOM 转为 Canvas 粒子,那么输入自然是 DOM 。这里预设了两种粒子效果,就如开篇的图所示。

获取图像数据

调用方法,传入 DOM 和 动画类型初始化后,直接就是获取图像数据,这些数据就是后面要创建的粒子。

自己传入进来的 DOM 什么样,就能截图显示成什么样?(当然,html2canvas 的小缺陷还是避免不了,比如跨域图片的加载 。)

然后除了图像数据外,还有 DOM 的尺寸也要记录下来,到时候在画布上渲染需要用得到。

开始动画

初始化好后,自然不一定希望立即动画,所以导出了一个 startAnimation 方法,一旦调用就开始动画。

而这个方法,自然有几处逻辑上的需要考虑,比如上一次的动画需要清除,动画的持续时间,动画结束之后又要清除以防内存泄露等等。考虑好后,自然就是逻辑上的开发了。

动画渲染

终于到了关键的一步,而这里却很简单。

几个步骤:

  1. 调用动画方法后,增加一个 Canvas 画布,用于渲染粒子。
  2. requestAnimationFrame 渲染动画。
  3. html2canvas 获取的图像数据,遍历创建粒子,这些粒子的位置随 requestAnimationFrame 改变。

核心逻辑就是这样,不过还有一些小细节要考虑。比如要更新一下传入 DOM 的位置,放置窗口 Resize 或者页面 Scroll 造成的位置影响。或者粒子的动画效果该如何去设置。不过这些都是优化项,主要初步的能渲染就行,粒子的动画效果无非就是改变 x || y 值,做匀速、匀加速、正弦余弦波动,几种组合在一起,整的花里胡哨的。

然后还有就是粒子的数量对浏览器的 FPS 的影响。

使用方法

经过两天的时间,开发了一个 html2particle NPM 包,并写了一个简要的说明文档和用法示例。使用 TS 开发的,编译成 JS 发布上去的,所以使用也无关前端框架,都可以使用。这里只放一个 Vue 版本(包括样式)的示例,用 Vitepress 写的说明文档还有原生和 React 的用法。

vue

vue 复制代码
<script setup lang="ts">
import { onMounted, ref } from 'vue'
import html2particle from 'html2particle'

const item4Ref = ref<HTMLElement>()
let handleItem4Click = () => { }
const isShow4 = ref(true)
function initItem4Event() {
  const { startAnimation } = html2particle(item4Ref.value!, { type: 'ExplodingParticle' })
  handleItem4Click = () => {
    isShow4.value = false
    startAnimation()
  }
}

const item5Ref = ref<HTMLElement>()
let handleItem5Click = () => { }
const isShow5 = ref(true)
function initItem5Event() {
  const { startAnimation } = html2particle(item5Ref.value!, { type: 'SinWaveParticle' })
  handleItem5Click = () => {
    isShow5.value = false
    startAnimation()
  }
}

onMounted(() => {
  initItem4Event()
  initItem5Event()
})
</script>

<template>
  <div class="container">
    <div ref="item4Ref" class="image" @click="handleItem4Click">
      <img v-if="isShow4" src="/1.jpg" alt="">
    </div>

    <div ref="item5Ref" class="image" @click="handleItem5Click">
      <img v-if="isShow5" src="/2.jpg" alt="">
    </div>
  </div>
</template>

<style scoped>
.container {
  align-items: center;
  user-select: none;
  display: flex;
  flex-direction: row;
}

.image {
  width: 300px;
  height: 200px;
  cursor: pointer;
  margin: 0 auto 20px;
  display: flex;
  justify-content: center;
  align-items: center;
}

img {
  object-fit: cover;
  width: 100%;
  height: 100%;
  border-radius: 10px;
  overflow: hidden;
  outline: 2px solid #887cc8;
  outline-offset: 2px;
}
</style>

结尾

总的来说,因为样式炫目,才引起的兴趣研究一下这个。虽然代码量不多,不过还是有点意思。如果可以自定义传入粒子效果,而不是只有这两种,那应该更好用些。

Demo 及文档预览 : html2particle.mmeme.me/guide/demo....

NPM 包地址 : www.npmjs.com/package/htm...

GitHub 仓库地址 : github.com/pinky-pig/h...

相关推荐
vortex51 小时前
深度字典攻击(实操笔记·红笔思考)
前端·chrome·笔记
我是伪码农1 小时前
Vue 1.30
前端·javascript·vue.js
利刃大大1 小时前
【Vue】默认插槽 && 具名插槽 && 作用域插槽
前端·javascript·vue.js
艳阳天_.1 小时前
web 分录科目实现辅助账
开发语言·前端·javascript
小白64021 小时前
2025年终总结-迷途漫漫,终有一归
前端·程序人生
烟花落o1 小时前
贪吃蛇及相关知识点讲解
c语言·前端·游戏开发·贪吃蛇·编程学习
晚霞的不甘2 小时前
Flutter for OpenHarmony专注与习惯的完美融合: 打造你的高效生活助手
前端·数据库·经验分享·flutter·前端框架·生活
kogorou0105-bit2 小时前
前端设计模式:发布订阅与依赖倒置的解耦之道
前端·设计模式·面试·状态模式
止观止2 小时前
像三元表达式一样写类型?深入理解 TS 条件类型与 `infer` 推断
前端·typescript
雪芽蓝域zzs2 小时前
uniapp 省市区三级联动
前端·javascript·uni-app