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

相关推荐
egekm_sefg37 分钟前
一个基于Rust适用于 Web、桌面、移动设备等的全栈应用程序框架
开发语言·前端·rust
ObjectX前端实验室1 小时前
交互式md文档渲染实现
前端·github·markdown
小怪瘦791 小时前
JS实现Table表格数据跑马灯效果
开发语言·javascript·信息可视化
励志成为大佬的小杨2 小时前
c语言中的枚举类型
java·c语言·前端
罗_三金2 小时前
微信小程序打印生产环境日志
javascript·微信小程序·小程序·bug
shuishen492 小时前
Web Bluetooth API 开发记录
javascript·web·js
前端熊猫2 小时前
Element Plus 日期时间选择器大于当天时间置灰
前端·javascript·vue.js
傻小胖2 小时前
React 组件通信完整指南 以及 自定义事件发布订阅系统
前端·javascript·react.js
JaxNext3 小时前
开发 AI 应用的无敌配方,半小时手搓学英语利器
前端·javascript·aigc
万亿少女的梦1683 小时前
高校网络安全存在的问题与对策研究
java·开发语言·前端·网络·数据库·python