H5 鼠标点击粒子扩散效果

🧐别人的博客中有这样的效果,于是自己就尝试实现了一下。

效果如图

源码如下

html 复制代码
<!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 / 2
            let cy = height / 2

            class 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 = color

                    this.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 * proportion
                        this.y = y + ty * proportion
                        this.r = r * (1 - timeProportion)

                        ctx.fillStyle = color
                        ctx.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() - 1
                let 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

相关推荐
_.Switch1 小时前
Python Web 应用中的 API 网关集成与优化
开发语言·前端·后端·python·架构·log4j
一路向前的月光1 小时前
Vue2中的监听和计算属性的区别
前端·javascript·vue.js
长路 ㅤ   1 小时前
vite学习教程06、vite.config.js配置
前端·vite配置·端口设置·本地开发
长路 ㅤ   1 小时前
vue-live2d看板娘集成方案设计使用教程
前端·javascript·vue.js·live2d
Fan_web1 小时前
jQuery——事件委托
开发语言·前端·javascript·css·jquery
安冬的码畜日常1 小时前
【CSS in Depth 2 精译_044】第七章 响应式设计概述
前端·css·css3·html5·响应式设计·响应式
莹雨潇潇2 小时前
Docker 快速入门(Ubuntu版)
java·前端·docker·容器
Jiaberrr2 小时前
Element UI教程:如何将Radio单选框的圆框改为方框
前端·javascript·vue.js·ui·elementui
Tiffany_Ho3 小时前
【TypeScript】知识点梳理(三)
前端·typescript
安冬的码畜日常4 小时前
【D3.js in Action 3 精译_029】3.5 给 D3 条形图加注图表标签(上)
开发语言·前端·javascript·信息可视化·数据可视化·d3.js