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

相关推荐
程序员爱技术5 分钟前
Vue 2 + JavaScript + vue-count-to 集成案例
前端·javascript·vue.js
并不会1 小时前
常见 CSS 选择器用法
前端·css·学习·html·前端开发·css选择器
悦涵仙子1 小时前
CSS中的变量应用——:root,Sass变量,JavaScript中使用Sass变量
javascript·css·sass
衣乌安、1 小时前
【CSS】居中样式
前端·css·css3
兔老大的胡萝卜1 小时前
ppk谈JavaScript,悟透JavaScript,精通CSS高级Web,JavaScript DOM编程艺术,高性能JavaScript pdf
前端·javascript
低代码布道师1 小时前
CSS的三个重点
前端·css
耶啵奶膘3 小时前
uniapp-是否删除
linux·前端·uni-app
王哈哈^_^4 小时前
【数据集】【YOLO】【目标检测】交通事故识别数据集 8939 张,YOLO道路事故目标检测实战训练教程!
前端·人工智能·深度学习·yolo·目标检测·计算机视觉·pyqt
cs_dn_Jie5 小时前
钉钉 H5 微应用 手机端调试
前端·javascript·vue.js·vue·钉钉
开心工作室_kaic5 小时前
ssm068海鲜自助餐厅系统+vue(论文+源码)_kaic
前端·javascript·vue.js