🧐别人的博客中有这样的效果,于是自己就尝试实现了一下。
效果如图
源码如下
<!DOCTYPE html>
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible" content="IE=edge"><meta name="viewport" content="width=device-width, initial-scale=1.0"><link rel="stylesheet" href="./assets/global.css"><style>.blastParticle {position: absolute;transform: translate(-50%, -50%);pointer-events: none;}body {overflow: hidden;}.hint-text {display: flex;align-items: center;justify-content: center;width: 100vw;height: 100vh;user-select: none;}</style>
</head><body><div class="hint-text">点击鼠标左键,查看粒子效果</div><script type="module">import { Randoms } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/randoms.js";import { Animation } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/animation.js";import { Maths } from "https://gcore.jsdelivr.net/npm/@3r/tool/lib/maths.js";/*** 爆炸粒子效果*/function blastParticle(params = {}) {let { left = 0, top = 0, width = 200, height = 200, count = 20, rr = [10, 20], duration = 1 } = params// 通过recovery拾取回收canvas 减少dom产生量let canvas = document.querySelector('canvas.blastParticle.recovery') || document.createElement("canvas")canvas.classList.remove('recovery')let ctx = canvas.getContext('2d')canvas.width = width;canvas.height = height;canvas.classList.add('blastParticle')canvas.style.left = left + 'px'canvas.style.top = top + 'px'let cx = width / 2let cy = height / 2class Particle {constructor({ x, y, r, tx, ty, ts, color, duration }) {this.x = x;this.y = y;this.r = r;this.tx = tx;this.ty = ty;this.ts = ts;this.color = colorthis.timestemp = +new Date()this.update = () => {if ((+new Date() - this.timestemp) > 1000 * duration) return;let timeProportion = (+new Date() - this.timestemp) / (1000 * duration)let proportion = Animation.easeOut(timeProportion)this.x = x + tx * proportionthis.y = y + ty * proportionthis.r = r * (1 - timeProportion)ctx.fillStyle = colorctx.beginPath()ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2)ctx.closePath();ctx.fill()}}}// 记录开始时间 用于停止渲染标记let startTimestemp = +new Date()function renderer(particles) {ctx.clearRect(0, 0, width, height)for (const p of particles) {p.update()}if (+new Date() - startTimestemp < duration * 1000) {console.log("渲染中");requestAnimationFrame(() => { renderer(particles) })}else {console.log('渲染结束');canvas.classList.add('recovery');}}// 粒子列表let particleList = []for (let i = 0; i < count; i++) {// 随机方向let tx = 2 * Math.random() - 1let ty = 2 * Math.random() - 1// 乘以半径tx *= cx;ty *= cy;let particle = new Particle({ x: cx, y: cy, r: Randoms.getRandomInt(...rr), tx, ty, ts: 0, duration, color: Randoms.getRandomColor() })particleList.push(particle)}// 执行渲染renderer(particleList)document.body.appendChild(canvas)}document.addEventListener("click", (ev) => {blastParticle({ left: ev.x, top: ev.y, duration: .5 })})</script>
</body></html>
在线预览
https://linyisonger.github.io/H5.Examples/
源码仓库
https://github.com/linyisonger/H5.Examples.git