效果

V 阿呆 (UID: 1) 站长 [复制链接]
帖子链接已复制到剪贴板
帖子已经有人评论啦,不支持删除!

5950 0
<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>文字防剧透效果示例</title>
    <style>
       .spoiler {
            cursor: pointer;
            display: inline-block;
            position: relative;
        }

       .spoiler-content {
            padding: 10px;
            clip-path: circle(0% at 50% 50%);
            transition: clip-path 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
        }

       .spoiler.revealed .spoiler-content {
            clip-path: circle(100% at 50% 50%);
        }

        #particle-canvas {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            transition: opacity 0.8s cubic-bezier(0.25, 0.1, 0.25, 1);
        }

       .spoiler.revealed #particle-canvas {
            opacity: 0;
        }

       .spoiler:not(.revealed) #particle-canvas {
            opacity: 1;
        }
    </style>
</head>

<body>
    <div class="spoiler" onclick="toggleSpoiler(this)">
        <div class="spoiler-content">这是一段初始被隐藏的内容,点击粒子动画消失后就会显示</div>
        <canvas id="particle-canvas"></canvas>
    </div>
    <script>
        const canvas = document.getElementById('particle-canvas');
        const ctx = canvas.getContext('2d');
        const particles = [];
        const particleCount = 800;

        canvas.width = canvas.offsetWidth;
        canvas.height = canvas.offsetHeight;

        const centerX = canvas.width / 2;
        const centerY = canvas.height / 2;

        function getWeightedPosition(max) {
            const margin = 0.1;
            let pos;
            do {
                pos = Math.random() * max;
                const distanceToEdge = Math.min(pos, max - pos);
                const weight = distanceToEdge / (max * margin);
                if (Math.random() < weight) {
                    break;
                }
            } while (true);
            return pos;
        }

        class Particle {
            constructor() {
                this.x = getWeightedPosition(canvas.width);
                this.y = getWeightedPosition(canvas.height);
                this.size = Math.random() * 1 + 0.2;
                this.speedX = (Math.random() - 0.5) * 2;
                this.speedY = (Math.random() - 0.5) * 2;
                this.opacity = 1;
            }

            update() {
                this.x += this.speedX;
                this.y += this.speedY;

                if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) {
                    this.toRemove = true;
                }
            }

            draw() {
                if (!this.toRemove) {
                    ctx.beginPath();
                    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                    ctx.fillStyle = `rgba(0, 0, 0, ${this.opacity})`;
                    ctx.fill();
                }
            }

            fadeOut(revealProgress) {
                const distance = Math.sqrt((this.x - centerX) ** 2 + (this.y - centerY) ** 2);
                const maxDistance = Math.sqrt(centerX ** 2 + centerY ** 2);
                const fadeThreshold = revealProgress * maxDistance;
                if (distance < fadeThreshold) {
                    this.opacity = Math.max(0, this.opacity - 0.05);
                }
            }
        }

        function initParticles() {
            for (let i = 0; i < particleCount; i++) {
                particles.push(new Particle());
            }
        }

        let revealProgress = 0;
        let isRevealing = false;

        function animate() {
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            if (isRevealing) {
                revealProgress = Math.min(1, revealProgress + 0.02);
            }

            for (let i = particles.length - 1; i >= 0; i--) {
                const particle = particles[i];
                particle.update();
                if (isRevealing) {
                    particle.fadeOut(revealProgress);
                }
                if (particle.toRemove) {
                    particles.splice(i, 1);
                } else {
                    particle.draw();
                }
            }

            // 检查粒子数量,不足则生成新粒子
            while (particles.length < particleCount) {
                particles.push(new Particle());
            }

            requestAnimationFrame(animate);
        }

        function toggleSpoiler(element) {
            element.classList.toggle('revealed');
            if (element.classList.contains('revealed')) {
                isRevealing = true;
            } else {
                isRevealing = false;
                revealProgress = 0;
                particles.forEach(particle => {
                    particle.opacity = 1;
                    particle.toRemove = false;
                });
            }
        }

        initParticles();
        animate();
    </script>
</body>

</html>
    

 

<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>遮挡图片效果示例</title>
    <style>
       .spoiler {
            cursor: pointer;
            display: inline-block;
            position: relative;
        }

       .spoiler-content {
            padding: 10px;
            position: relative;
        }

       .spoiler-image {
            /* 加深毛玻璃效果,将模糊半径从 10px 增加到 20px */
            filter: blur(20px);
            transition: filter 1.2s cubic-bezier(0.25, 0.1, 0.25, 1);
        }

       .spoiler.revealed .spoiler-image {
            filter: blur(0);
        }

       .particle-mask {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: auto;
            transition: opacity 1.2s cubic-bezier(0.25, 0.1, 0.25, 1);
            opacity: 1;
        }

       .spoiler.revealed .particle-mask {
            opacity: 0;
        }
    </style>
</head>

<body>
    <div class="spoiler" id="spoiler-container">
        <div class="spoiler-content">
            <img class="spoiler-image" id="spoiler-img" src="https://www.meidecloud.com/xc.jpg" alt="图片" />
            <div class="particle-mask">
                <canvas id="particle-canvas"></canvas>
            </div>
        </div>
    </div>
    <script>
        const canvas = document.getElementById('particle-canvas');
        const img = document.getElementById('spoiler-img');
        const ctx = canvas.getContext('2d');
        const particles = [];
        let bubble;
        const density = 0.01; // 粒子密度,可根据需要调整
        let particleCount = 0;
        const spoilerContainer = document.getElementById('spoiler-container');

        img.onload = function () {
            canvas.width = img.width;
            canvas.height = img.height;
            const centerX = canvas.width / 2;
            const centerY = canvas.height / 2;

            // 根据图片面积动态计算粒子数量
            particleCount = Math.floor(canvas.width * canvas.height * density);

            function getWeightedPosition(max) {
                const margin = 0.1;
                let pos;
                do {
                    pos = Math.random() * max;
                    const distanceToEdge = Math.min(pos, max - pos);
                    const weight = distanceToEdge / (max * margin);
                    if (Math.random() < weight) {
                        break;
                    }
                } while (true);
                return pos;
            }

            class Particle {
                constructor() {
                    this.x = getWeightedPosition(canvas.width);
                    this.y = getWeightedPosition(canvas.height);
                    this.size = Math.random() * 1 + 0.2;
                    this.speedX = (Math.random() - 0.5) * 2;
                    this.speedY = (Math.random() - 0.5) * 2;
                    this.opacity = 1;
                }

                update() {
                    this.x += this.speedX;
                    this.y += this.speedY;

                    if (this.x < 0 || this.x > canvas.width || this.y < 0 || this.y > canvas.height) {
                        this.toRemove = true;
                    }
                }

                draw() {
                    if (!this.toRemove) {
                        ctx.beginPath();
                        ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
                        ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`;
                        ctx.fill();
                    }
                }

                fadeOut(revealProgress) {
                    const distance = Math.sqrt((this.x - centerX) ** 2 + (this.y - centerY) ** 2);
                    const maxDistance = Math.sqrt(centerX ** 2 + centerY ** 2);
                    const fadeThreshold = revealProgress * maxDistance;
                    if (distance < fadeThreshold) {
                        this.opacity = Math.max(0, this.opacity - 0.05);
                    }
                }
            }

            class Bubble {
                constructor(x, y) {
                    this.x = x;
                    this.y = y;
                    this.radius = 0;
                    this.maxRadius = Math.max(canvas.width, canvas.height);
                    this.opacity = 0.8; // 初始透明度
                    this.speed = 2;
                }

                update() {
                    this.radius += this.speed;
                    this.opacity = Math.max(0, this.opacity - 0.01); // 逐渐降低透明度
                    if (this.radius >= this.maxRadius) {
                        this.toRemove = true;
                    }
                }

                draw() {
                    if (!this.toRemove) {
                        ctx.beginPath();
                        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
                        ctx.fillStyle = `rgba(255, 255, 255, ${this.opacity})`; // 白色透明填充
                        ctx.fill();
                        ctx.strokeStyle = `rgba(255, 255, 255, ${this.opacity})`;
                        ctx.lineWidth = 2;
                        ctx.stroke();
                    }
                }
            }

            function createBubble(x, y) {
                bubble = new Bubble(x, y);
            }

            function initParticles() {
                for (let i = 0; i < particleCount; i++) {
                    particles.push(new Particle());
                }
            }

            let revealProgress = 0;
            let isRevealing = false;

            function animate() {
                ctx.clearRect(0, 0, canvas.width, canvas.height);

                if (isRevealing) {
                    revealProgress = Math.min(1, revealProgress + 0.02);
                }

                for (let i = particles.length - 1; i >= 0; i--) {
                    const particle = particles[i];
                    particle.update();
                    if (isRevealing) {
                        particle.fadeOut(revealProgress);
                    }
                    if (particle.toRemove) {
                        particles.splice(i, 1);
                    } else {
                        particle.draw();
                    }
                }

                if (bubble) {
                    bubble.update();
                    if (bubble.toRemove) {
                        bubble = null;
                    } else {
                        bubble.draw();
                        // 根据气泡半径控制图片显示区域
                        ctx.globalCompositeOperation = 'destination-in';
                        ctx.beginPath();
                        ctx.arc(bubble.x, bubble.y, bubble.radius, 0, Math.PI * 2);
                        ctx.fill();
                        ctx.globalCompositeOperation = 'source-over';
                    }
                }

                // 绘制气泡遮罩
                if (isRevealing) {
                    ctx.globalCompositeOperation = 'destination-in';
                    ctx.fillStyle = `rgba(255, 255, 255, ${revealProgress})`;
                    ctx.fillRect(0, 0, canvas.width, canvas.height);
                    ctx.globalCompositeOperation = 'source-over';
                }

                // 检查粒子数量,不足则生成新粒子
                while (particles.length < particleCount) {
                    particles.push(new Particle());
                }

                requestAnimationFrame(animate);
            }

            function toggleSpoiler() {
                spoilerContainer.classList.toggle('revealed');
                if (spoilerContainer.classList.contains('revealed')) {
                    isRevealing = true;
                    const centerX = canvas.width / 2;
                    const centerY = canvas.height / 2;
                    createBubble(centerX, centerY);
                } else {
                    isRevealing = false;
                    revealProgress = 0;
                    particles.forEach(particle => {
                        particle.opacity = 1;
                        particle.toRemove = false;
                    });
                    bubble = null;
                }
            }

            spoilerContainer.addEventListener('click', toggleSpoiler);

            initParticles();
            animate();
        };
    </script>
</body>

</html>
    
本人发表的文字只是用来测试键盘是否可用,不代表本人立场
已有评论 ( 0 )
提示:您必须 登录 才能查看此内容。
创建新帖
自助推广点击空位自助购买TG联系
确认删除
确定要删除这篇帖子吗?删除后将无法恢复。
删除成功
帖子已成功删除,页面将自动刷新。
删除失败
删除帖子时发生错误,请稍后再试。