杀马特风格特效 2 代网页源码分享xiuno适配代码提供

基于 杀马特风格特效 2 代网页源码分享 得来,实现了对评论区用户的 juejue 调教,并支持图片下载。

杀马特风格特效 2 代网页源码分享xiuno适配代码提供

触发方式:评论区 hover 对方头像或昵称 2 秒

杀马特风格特效 2 代网页源码分享xiuno适配代码提供

二次 juejue 保护,等消肿了再来吧~

杀马特风格特效 2 代网页源码分享xiuno适配代码提供

适配 xiuno 程序:

头部添加定义

<script>
window.visitUser = {
    uid: '<?php echo htmlspecialchars($user['uid'], ENT_QUOTES);?>',
    username: '<?php echo htmlspecialchars($user['username'], ENT_QUOTES);?>',
    avatarUrl: '<?php echo htmlspecialchars($user['avatar_url'], ENT_QUOTES);?>'
};
</script>
JavaScript

修改评论文件 post_list.inc.htm ,在输出评论者头像与昵称的 <a></a > 标签中添加

data-owner-uid="<?php echo htmlspecialchars($_post['uid'], ENT_QUOTES);?>"
data-owner-name="<?php echo htmlspecialchars($_post['username'], ENT_QUOTES);?>" 
data-owner-avatar="<?php echo htmlspecialchars($_post['user_avatar_url'], ENT_QUOTES);?>" 
Markup

最后,在帖子页底部添加

<script type='text/javascript'>
document.addEventListener('DOMContentLoaded', function() {
    const visitUser = window.visitUser || {};
    if (!visitUser.uid || visitUser.uid === '0' || visitUser.uid === '') {
        return;
    }

    const JUE_COOLDOWN = 10 * 60 * 1000;
    const EFFECT_DURATION = 10 * 1000;
    const TIP_DURATION = 2000;
    const HOVER_DELAY = 2000;
    const FRAME_DELAY = 80;
    let hoverTimer = null;
    let currentFloorData = null;
    let smartbgm = null;
    let effectTimer = null;
    let animationFrameId = null;
    let currentFrame = 0;
    let lastFrameTime = 0;
    let canvas = null;
    let ctx = null;
    let customMenu = null; 
    let isMenuShow = false; 

    const images = {
        bg: [null, null, null],
        visitAvatar: null,
        ownerAvatar: null
    };

    const visitAvatarPositions = {
        1: { x: 106 + 54, y: -7 + 54, size: 108 },
        2: { x: 99 + 54, y: 3 + 54, size: 108 },
        3: { x: 118 + 54, y: -11 + 54, size: 108 }
    };

    const ownerAvatarPositions = {
        1: { x: 0 + 53, y: 157 + 53, size: 106, rotation: -90 },
        2: { x: 10 + 53, y: 153 + 53, size: 106, rotation: -90 },
        3: { x: 3 + 53, y: 140 + 53, size: 106, rotation: -90 }
    };

    function stripHtml(html) {
        if (!html) return '';
        return html.replace(/<[^>]+>/g, '').trim();
    }

    function injectBaseStyles() {
        const style = document.createElement('style');
        style.textContent = `
            #jue-canvas-container { user-select: none; }
            #jue-canvas { cursor: default; }
            #jue-custom-menu {
                position: fixed; z-index: 10000; background: white;
                border-radius: 4px; box-shadow: 0 2px 8px rgba(0,0,0,0.2);
                padding: 4px 0; margin: 0; list-style: none; display: none;
            }
            #jue-custom-menu li {
                padding: 6px 16px; cursor: pointer; white-space: nowrap;
            }
            #jue-custom-menu li:hover {
                background: #f5f5f5;
            }
        `;
        document.head.append(style);
    }

    function createCustomRightMenu() {
        if (document.getElementById('jue-custom-menu')) {
            customMenu = document.getElementById('jue-custom-menu');
            return;
        }

        customMenu = document.createElement('ul');
        customMenu.id = 'jue-custom-menu';

        const downloadItem = document.createElement('li');
        downloadItem.innerText = '下载图片';
        downloadItem.addEventListener('click', function() {
            downloadCanvasAsCustomName();
            hideCustomMenu();
        });

        customMenu.append(downloadItem);
        document.body.append(customMenu);
    }

    function showCustomMenu(e) {
        if (!customMenu) createCustomRightMenu();

        const menuWidth = customMenu.offsetWidth;
        const menuHeight = customMenu.offsetHeight;
        const winWidth = window.innerWidth;
        const winHeight = window.innerHeight;

        let left = e.clientX + 10;
        let top = e.clientY + 10;

        if (left + menuWidth > winWidth) left = e.clientX - menuWidth - 10;
        if (top + menuHeight > winHeight) top = e.clientY - menuHeight - 10;

        customMenu.style.left = `${left}px`;
        customMenu.style.top = `${top}px`;
        customMenu.style.display = 'block';
        isMenuShow = true;
    }

    function hideCustomMenu() {
        if (customMenu) {
            customMenu.style.display = 'none';
            isMenuShow = false;
        }
    }

    function createConfirmModal() {
        if (document.getElementById('jue-modal')) return;

        const modal = document.createElement('div');
        modal.id = 'jue-modal';
        modal.style.cssText = `
            position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;
            background: rgba(0,0,0,0.5); z-index: 9999; display: flex;
            align-items: center; justify-content: center;
        `;

        const modalContent = document.createElement('div');
        modalContent.id = 'jue-modal-content';
        modalContent.style.cssText = `
            background: white; padding: 24px; border-radius: 8px;
            width: 90%; max-width: 400px; text-align: center;
        `;

        const modalText = document.createElement('p');
        modalText.id = 'jue-modal-text';
        const cleanVisitName = stripHtml(visitUser.username);
        const cleanOwnerName = stripHtml(currentFloorData.ownerName);
        modalText.innerText = `尊敬的${cleanVisitName},您似乎对${cleanOwnerName}有点想法?要不要Jue他?`;
        modalText.style.marginBottom = '20px';

        const btnContainer = document.createElement('div');
        btnContainer.id = 'jue-modal-btn';
        btnContainer.style.display = 'flex';
        btnContainer.style.gap = '12px';
        btnContainer.style.justifyContent = 'center';

        const cancelBtn = document.createElement('button');
        cancelBtn.innerText = '否';
        cancelBtn.style.cssText = `
            padding: 8px 24px; border: none; border-radius: 4px;
            background: #eee; cursor: pointer;
        `;
        cancelBtn.onclick = () => modal.remove();

        const confirmBtn = document.createElement('button');
        confirmBtn.innerText = '是';
        confirmBtn.style.cssText = `
            padding: 8px 24px; border: none; border-radius: 4px;
            background: #3b82f6; color: white; cursor: pointer;
        `;
        confirmBtn.onclick = handleJueConfirm;

        btnContainer.append(cancelBtn, confirmBtn);
        modalContent.append(modalText, btnContainer);
        modal.append(modalContent);
        document.body.append(modal);
    }

    function handleJueConfirm() {
        const modal = document.getElementById('jue-modal');
        const modalText = document.getElementById('jue-modal-text');
        const btnContainer = document.getElementById('jue-modal-btn');

        const juedUsersStr = localStorage.getItem('juedUsers') || '{}';
        const juedUsers = JSON.parse(juedUsersStr);
        const currentOwnerUid = currentFloorData.ownerUid;

        if (juedUsers[currentOwnerUid] && Date.now() - juedUsers[currentOwnerUid] < JUE_COOLDOWN) {
            const cleanOwnerName = stripHtml(currentFloorData.ownerName);
            modalText.innerText = `您刚刚已经jue过${cleanOwnerName}了,休息休息保存体力吧~`;
            btnContainer.remove();
            setTimeout(() => modal.remove(), TIP_DURATION);
            return;
        }

        juedUsers[currentOwnerUid] = Date.now();
        localStorage.setItem('juedUsers', JSON.stringify(juedUsers));

        modal.remove();
        createJueEffectContainer();
        loadImagesAndStartEffect();
    }

    function createJueEffectContainer() {
        const existingContainer = document.getElementById('jue-effect-container');
        if (existingContainer) existingContainer.remove();
        hideCustomMenu();

        const effectContainer = document.createElement('div');
        effectContainer.id = 'jue-effect-container';
        effectContainer.style.cssText = `
            position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
            z-index: 9998; background: transparent; text-align: center;
        `;

        const canvasContainer = document.createElement('div');
        canvasContainer.id = 'jue-canvas-container';
        canvasContainer.style.cssText = `
            margin: 0 auto; position: relative; width: 270px; height: 270px;
        `;

        canvas = document.createElement('canvas');
        canvas.id = 'jue-canvas';
        canvas.width = 270;
        canvas.height = 270;
        canvas.style.width = '100%';
        canvas.style.height = '100%';
        ctx = canvas.getContext('2d');

        canvas.addEventListener('contextmenu', function(e) {
            e.preventDefault(); 
            showCustomMenu(e);
        });

        canvasContainer.append(canvas);
        effectContainer.append(canvasContainer);
        document.body.append(effectContainer);
    }

    function downloadCanvasAsCustomName() {
        if (!canvas) return;

        try {
            const cleanVisitName = stripHtml(visitUser.username) || '未知访客';
            const cleanOwnerName = (currentFloorData && stripHtml(currentFloorData.ownerName)) || '未知层主';
            const fileName = `${cleanVisitName}jue${cleanOwnerName}.png`;

            const dataURL = canvas.toDataURL('image/png');
            const link = document.createElement('a');
            link.href = dataURL;
            link.download = fileName;
            link.click();
        } catch (error) {
            console.error('图片保存失败:', error);
            alert('保存失败,可能存在跨域图片');
        }
    }

    function loadImagesAndStartEffect() {
        images.bg = [null, null, null];
        images.visitAvatar = null;
        images.ownerAvatar = null;
        
        images.visitAvatarUrl = visitUser.avatarUrl || '/tool/why/img/default-avatar.png';
        images.ownerAvatarUrl = currentFloorData.ownerAvatar || '/tool/why/img/default-avatar.png';
        
        let loadedCount = 0;
        const totalImages = 5;
        
        for (let i = 1; i <= 3; i++) {
            const img = new Image();
            img.crossOrigin = 'anonymous';
            img.src = `/tool/why/img/jue/${i}.png`;
            img.onload = function() {
                images.bg[i] = img;
                loadedCount++;
                if (loadedCount === totalImages) startJueEffect();
            };
            img.onerror = function() {
                console.error(`Failed to load background image ${i}`);
                loadedCount++;
                if (loadedCount === totalImages) startJueEffect();
            };
        }
        
        const visitImg = new Image();
        visitImg.crossOrigin = 'anonymous';
        visitImg.src = images.visitAvatarUrl;
        visitImg.onload = function() {
            images.visitAvatar = visitImg;
            loadedCount++;
            if (loadedCount === totalImages) startJueEffect();
        };
        visitImg.onerror = handleImageError;
        
        const ownerImg = new Image();
        ownerImg.crossOrigin = 'anonymous';
        ownerImg.src = images.ownerAvatarUrl;
        ownerImg.onload = function() {
            images.ownerAvatar = ownerImg;
            loadedCount++;
            if (loadedCount === totalImages) startJueEffect();
        };
        ownerImg.onerror = handleImageError;
        
        function handleImageError() {
            console.error("Failed to load avatar image");
            loadedCount++;
            if (loadedCount === totalImages) startJueEffect();
        }
    }

    function drawCircularAvatar(img, x, y, size, rotation = 0) {
        if (!img || !ctx) return;
        
        ctx.save();
        ctx.translate(x, y);
        if (rotation !== 0) ctx.rotate(rotation * Math.PI / 180);
        ctx.beginPath();
        ctx.arc(0, 0, size / 2, 0, Math.PI * 2);
        ctx.closePath();
        ctx.clip();
        ctx.drawImage(img, -size / 2, -size / 2, size, size);
        ctx.restore();
    }

    function drawCurrentFrame(frameNum) {
        if (!ctx || !images.bg[frameNum]) return;
        
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.drawImage(images.bg[frameNum], 0, 0, canvas.width, canvas.height);
        
        if (images.visitAvatar) {
            const pos = visitAvatarPositions[frameNum];
            drawCircularAvatar(images.visitAvatar, pos.x, pos.y, pos.size);
        }
        
        if (images.ownerAvatar) {
            const pos = ownerAvatarPositions[frameNum];
            drawCircularAvatar(images.ownerAvatar, pos.x, pos.y, pos.size, pos.rotation);
        }
    }

    function animate(timestamp) {
        if (!timestamp) timestamp = 0;
        
        if (timestamp - lastFrameTime >= FRAME_DELAY) {
            drawCurrentFrame(currentFrame + 1);
            currentFrame = (currentFrame + 1) % 3;
            lastFrameTime = timestamp;
        }
        
        animationFrameId = requestAnimationFrame(animate);
    }

    function startJueEffect() {
        if (!smartbgm) {
            smartbgm = new Audio('/tool/why/img/aaa.mp3');
            smartbgm.loop = true;
        }
        smartbgm.play().catch(() => {});
        
        currentFrame = 0;
        lastFrameTime = 0;
        drawCurrentFrame(1);
        animationFrameId = requestAnimationFrame(animate);
        
        setTimeout(() => {
            stopJueEffect();
            const effectContainer = document.getElementById('jue-effect-container');
            if (effectContainer) effectContainer.remove();
            hideCustomMenu(); 
        }, EFFECT_DURATION);
    }

    function stopJueEffect() {
        if (smartbgm) {
            smartbgm.pause();
            smartbgm.currentTime = 0;
        }
        if (animationFrameId) {
            cancelAnimationFrame(animationFrameId);
            animationFrameId = null;
        }
    }

    function bindFloorHoverEvent() {
        const floorTargets = document.querySelectorAll('.jue-floor-target');
        if (floorTargets.length === 0) return;

        floorTargets.forEach(target => {
            target.addEventListener('mouseenter', function() {
                currentFloorData = {
                    ownerUid: this.dataset.ownerUid || '',
                    ownerName: this.dataset.ownerName || '未知用户',
                    ownerAvatar: this.dataset.ownerAvatar || '/tool/why/img/default-avatar.png'
                };

                if (!currentFloorData.ownerUid || currentFloorData.ownerUid === visitUser.uid) return;
                hoverTimer = setTimeout(createConfirmModal, HOVER_DELAY);
            });

            target.addEventListener('mouseleave', () => {
                if (hoverTimer) {
                    clearTimeout(hoverTimer);
                    hoverTimer = null;
                }
            });
        });
    }

    function bindGlobalMenuCloseEvent() {
        document.addEventListener('click', function(e) {
            if (isMenuShow && !customMenu.contains(e.target)) {
                hideCustomMenu();
            }
        });

        document.addEventListener('keydown', function(e) {
            if (isMenuShow && e.key === 'Escape') {
                hideCustomMenu();
            }
        });
    }


    injectBaseStyles();
    createCustomRightMenu(); 
    bindGlobalMenuCloseEvent(); 
    bindFloorHoverEvent();
});
</script>
JavaScript

最最后,将附件下载解压到 /tool/why/ 目录下,或者你自定义位置解压,并修改上方 js 中的路径。

我用夸克网盘分享了「img_MG7YY.tar.gz」,点击链接即可保存。打开「夸克APP」,无需下载在线播放视频,畅享原画5倍速,支持电视投屏。
链接:https://pan.quark.cn/s/fb71c67c90a2

【版权声明】:服务器导航网所有内容均来自网络和部分原创,若无意侵犯到您的权利,请及时与联系 QQ 2232175042,将在48小时内删除相关内容!!

给TA服务器
共{{data.count}}人
人已服务器
其它源码

同城上门服务H5小程序源码

2025-11-1 7:18:19

美国服务器

HostDare,美国CN2 GIA VPS云服务器特价8折低至$28.79/年,美国洛杉矶Cera机房/最高100Mbps带宽,CN2 GIA/CU/CM优质网络

2023-9-5 8:26:36

0 条回复 A文章作者 M管理员
    暂无讨论,说说你的看法吧
个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索