炫酷粒子网页背景视觉特效

2026-06-04 程序代码 2 阅读 0 评论

最近弄了PiKa监控,它支持自定义JS,看到了一个粒子特效,就给它搞了一个,演示效果看图:
魔法悬浮粒子

代码如下:

(function () {
    // 控制开关:0=静态不跟随鼠标,1=正常跟随鼠标
    var mouseSwitch = 1;

    function init() {
        if (!document.body) {
            setTimeout(init, 100);
            return;
        }

        var canvasContainer = document.createElement('div');
        canvasContainer.style.cssText = `
          position: fixed;
          top: 0;
          left: 0;
          width: 100%;
          height: 100%;
          z-index: 99999;
          pointer-events: none;
        `;
        var canvas = document.createElement('canvas');
        canvas.id = 'tyParticlesCanvas';
        canvasContainer.appendChild(canvas);
        document.body.appendChild(canvasContainer);

        var ctx = canvas.getContext('2d');
        var particles = [];
        var dpr = window.devicePixelRatio || 1;

        var mouse = {
            x: window.innerWidth / 2,
            y: window.innerHeight / 2,
            tx: window.innerWidth / 2,
            ty: window.innerHeight / 2,
            active: false,
            radius: 190
        };

        var scroll = {
            lastY: window.pageYOffset || document.documentElement.scrollTop || 0,
            velocity: 0,
            targetVelocity: 0,
            direction: 0,
            burst: 0,
            targetBurst: 0
        };

        var colors = [
            { r: 255, g: 79, b: 163 },
            { r: 139, g: 92, b: 246 },
            { r: 103, g: 232, b: 249 },
            { r: 255, g: 124, b: 195 },
            { r: 80, g: 220, b: 120 },
            { r: 255, g: 210, b: 80 },
            { r: 230, g: 70, b: 80 },
            { r: 90, g: 170, b: 255 },
            { r: 255, g: 100, b: 70 },
            { r: 170, g: 255, b: 220 },
            { r: 200, g: 150, b: 255 },
            { r: 255, g: 245, b: 110 },
            { r: 60, g: 190, b: 190 },
            { r: 245, g: 130, b: 220 },
            { r: 155, g: 225, b: 90 }
        ];

        function rgba(c, a) {
            return 'rgba(' + c.r + ',' + c.g + ',' + c.b + ',' + a + ')';
        }

        function resizeCanvas() {
            var width = window.innerWidth;
            var height = window.innerHeight;
            canvas.width = width * dpr;
            canvas.height = height * dpr;
            canvas.style.width = width + 'px';
            canvas.style.height = height + 'px';
            ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
            createParticles();
        }

        function particleCount() {
            var w = window.innerWidth;
            if (w < 576) return 30;
            if (w < 992) return 55;
            return 135;
        }

        function createParticles() {
            particles = [];
            var count = particleCount();
            for (var i = 0; i < count; i++) {
                var color = colors[Math.floor(Math.random() * colors.length)];
                particles.push({
                    x: Math.random() * window.innerWidth,
                    y: Math.random() * window.innerHeight,
                    vx: (Math.random() - 0.5) * 0.28,
                    vy: (Math.random() - 0.5) * 0.28,
                    size: Math.random() * 4.5 + 0.75,
                    color: color,
                    alpha: Math.random() * 0.45 + 0.35,
                    floatOffset: Math.random() * Math.PI * 2,
                    floatSpeed: Math.random() * 0.008 + 0.004,
                    depth: Math.random() * 1.4 + 0.35,
                    inertiaY: 0,
                    inertiaX: 0
                });
            }
        }

        function updateMouse() {
            mouse.x += (mouse.tx - mouse.x) * 0.08;
            mouse.y += (mouse.ty - mouse.y) * 0.08;
        }

        function updateScrollVelocity() {
            var currentY = window.pageYOffset || document.documentElement.scrollTop || 0;
            var diff = currentY - scroll.lastY;
            scroll.lastY = currentY;
            if (diff > 0) scroll.direction = 1;
            else if (diff < 0) scroll.direction = -1;
            else scroll.direction = 0;
            scroll.targetVelocity = diff * 0.075;
            scroll.targetBurst = Math.max(-18, Math.min(18, diff * 0.18));
            scroll.velocity += (scroll.targetVelocity - scroll.velocity) * 0.12;
            scroll.burst += (scroll.targetBurst - scroll.burst) * 0.18;
            scroll.velocity *= 0.91;
            scroll.burst *= 0.88;
            scroll.targetBurst *= 0.72;
        }

        function drawParticle(p) {
            ctx.beginPath();
            ctx.arc(p.x, p.y, p.size, 0, Math.PI * 2);
            ctx.fillStyle = rgba(p.color, p.alpha);
            ctx.shadowBlur = 16;
            ctx.shadowColor = rgba(p.color, .85);
            ctx.fill();
            ctx.shadowBlur = 0;
        }

        function updateParticle(p, time) {
            var floatX = Math.cos(time * p.floatSpeed + p.floatOffset) * 0.35;
            var floatY = Math.sin(time * p.floatSpeed + p.floatOffset) * 0.35;
            var scrollDriftY = -scroll.velocity * p.depth;
            var scrollBurstY = -scroll.burst * p.depth * 0.16;
            var scrollDriftX = Math.sin(time * 0.001 + p.floatOffset) * Math.abs(scroll.velocity) * 0.08 * p.depth;
            p.inertiaY += scrollBurstY;
            p.inertiaX += scrollDriftX;
            p.inertiaY *= 0.88;
            p.inertiaX *= 0.90;
            p.x += p.vx + floatX + p.inertiaX;
            p.y += p.vy + floatY + scrollDriftY + p.inertiaY;

            // 通过mouseSwitch判断是否开启鼠标交互
            if (mouseSwitch === 1 && mouse.active) {
                var dx = mouse.x - p.x;
                var dy = mouse.y - p.y;
                var dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < mouse.radius) {
                    var force = (1 - dist / mouse.radius);
                    p.x += dx * force * 0.020;
                    p.y += dy * force * 0.020;
                    p.x += Math.sin(time * 0.004 + p.floatOffset) * force * 0.8;
                    p.y += Math.cos(time * 0.004 + p.floatOffset) * force * 0.8;
                }
            }

            if (p.x < -50) p.x = window.innerWidth + 50;
            if (p.x > window.innerWidth + 50) p.x = -50;
            if (p.y < -50) p.y = window.innerHeight + 50;
            if (p.y > window.innerHeight + 50) p.y = -50;
        }

        function connectParticles() {
            var maxDist = window.innerWidth < 576 ? 105 : 145;
            var scrollBoost = Math.min(Math.abs(scroll.velocity) * 0.018, 0.12);
            for (var i = 0; i < particles.length; i++) {
                for (var j = i + 1; j < particles.length; j++) {
                    var dx = particles[i].x - particles[j].x;
                    var dy = particles[i].y - particles[j].y;
                    var dist = Math.sqrt(dx * dx + dy * dy);
                    if (dist < maxDist) {
                        var opacity = (1 - dist / maxDist) * (0.16 + scrollBoost);
                        ctx.beginPath();
                        ctx.moveTo(particles[i].x, particles[i].y);
                        ctx.lineTo(particles[j].x, particles[j].y);
                        ctx.strokeStyle = 'rgba(255,124,195,' + opacity + ')';
                        ctx.lineWidth = 1.4;
                        ctx.stroke();
                    }
                }
            }
        }

        // 开关为0时不绘制鼠标连线
        function connectMouse() {
            if(mouseSwitch !== 1) return;
            if (!mouse.active) return;
            for (var i = 0; i < particles.length; i++) {
                var dx = mouse.x - particles[i].x;
                var dy = mouse.y - particles[i].y;
                var dist = Math.sqrt(dx * dx + dy * dy);
                if (dist < mouse.radius) {
                    var opacity = (1 - dist / mouse.radius) * 0.24;
                    ctx.beginPath();
                    ctx.moveTo(mouse.x, mouse.y);
                    ctx.lineTo(particles[i].x, particles[i].y);
                    ctx.strokeStyle = 'rgba(103,232,249,' + opacity + ')';
                    ctx.lineWidth = 1.4;
                    ctx.stroke();
                }
            }
        }

        function drawScrollWind() {
            var strength = Math.min(Math.abs(scroll.velocity) * 0.035, 0.22);
            if (strength < 0.015) return;
            var direction = scroll.direction || 1;
            var lineCount = 9;
            for (var i = 0; i < lineCount; i++) {
                var x = (window.innerWidth / lineCount) * i + Math.sin(Date.now() * 0.001 + i) * 28;
                var y = (Date.now() * 0.08 * direction + i * 120) % (window.innerHeight + 160) - 80;
                ctx.beginPath();
                ctx.moveTo(x, y);
                ctx.lineTo(x + 18 * direction, y - 90 * direction);
                ctx.strokeStyle = 'rgba(255,124,195,' + strength + ')';
                ctx.lineWidth = 1;
                ctx.stroke();
            }
        }

        function animate(time) {
            ctx.clearRect(0, 0, window.innerWidth, window.innerHeight);
            updateMouse();
            updateScrollVelocity();
            drawScrollWind();
            for (var i = 0; i < particles.length; i++) {
                updateParticle(particles[i], time);
                drawParticle(particles[i]);
            }
            connectParticles();
            connectMouse();
            requestAnimationFrame(animate);
        }

        window.addEventListener('resize', function () {
            dpr = window.devicePixelRatio || 1;
            resizeCanvas();
        });
        window.addEventListener('mousemove', function (e) {
            mouse.tx = e.clientX;mouse.ty = e.clientY;mouse.active = true;
        });
        window.addEventListener('mouseleave', function () { mouse.active = false; });
        window.addEventListener('touchmove', function (e) {
            if (!e.touches || !e.touches.length) return;
            mouse.tx = e.touches[0].clientX;mouse.ty = e.touches[0].clientY;mouse.active = true;
        }, { passive: true });
        window.addEventListener('touchend', function () { mouse.active = false; });

        resizeCanvas();
        requestAnimationFrame(animate);
    }
    init();
})();

本文链接:https://blog.clang.cn/840.html

版权声明:转载请注明出处。

评论 (0)

评论已关闭