Greasy Fork

Greasy Fork is available in English.

通用自动点击脚本(定时版 + 状态显示)

支持定时自动点击,并通过鼠标右键选择目标元素,实时显示运行状态、执行次数等信息。

当前为 2024-11-23 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         通用自动点击脚本(定时版 + 状态显示)
// @namespace    http://tampermonkey.net/
// @version      3.2
// @description  支持定时自动点击,并通过鼠标右键选择目标元素,实时显示运行状态、执行次数等信息。
// @author       Universal
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

(function () {
    'use strict';

    const CONFIG = {
        CONTROL_PANEL_ID: 'autoClickControl', // 控制面板ID
        OVERLAY_ID: 'elementOverlay', // 高亮层ID
        CLICK_INTERVAL: 500, // 每次点击间隔 (毫秒)
        MAX_CLICKS: 20, // 最大点击次数
    };

    const State = {
        targetSelector: GM_getValue('targetSelector', ''), // 目标选择器
        isPicking: false, // 是否正在选择目标元素
        isRunning: false, // 是否正在运行点击
        timer: null, // 定时器
        clickCount: 0, // 当前点击次数
        executeTime: GM_getValue('executeTime', ''), // 定时执行时间
        debug: true, // 是否启用调试日志
    };

    // 调试日志
    function debugLog(...args) {
        if (State.debug) console.log('[Debug]', ...args);
    }

    // 添加样式
    function addStyles() {
        GM_addStyle(`
            #autoClickControl {
                position: fixed;
                top: 10px;
                right: 10px;
                z-index: 9999;
                background: #fff;
                border: 1px solid #ccc;
                padding: 15px;
                border-radius: 5px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
                font-family: Arial, sans-serif;
                width: 300px;
            }
            #autoClickControl input, #autoClickControl button {
                margin-bottom: 10px;
            }
            #autoClickControl input {
                width: 100%;
                padding: 5px;
                border: 1px solid #ddd;
                border-radius: 3px;
            }
            #autoClickControl button {
                padding: 5px 10px;
                border: none;
                border-radius: 3px;
                cursor: pointer;
            }
            #autoClickControl #startButton {
                background-color: #28a745;
                color: white;
            }
            #autoClickControl #pickButton {
                background-color: #007bff;
                color: white;
            }
            #autoClickControl #stopButton {
                background-color: #dc3545;
                color: white;
            }
            #elementOverlay {
                position: absolute;
                border: 2px dashed #007bff;
                background-color: rgba(0, 123, 255, 0.2);
                pointer-events: none;
                z-index: 9998;
                display: none;
            }
            #statusText {
                font-size: 12px;
                color: #333;
            }
        `);
    }

    // 创建控制面板
    function createControlPanel() {
        if (document.getElementById(CONFIG.CONTROL_PANEL_ID)) return;

        const controlPanel = document.createElement('div');
        controlPanel.id = CONFIG.CONTROL_PANEL_ID;
        controlPanel.innerHTML = `
            <label>目标选择器 (CSS选择器或XPath):</label>
            <input type="text" id="targetSelectorInput" placeholder="通过右键选择或手动输入" value="${State.targetSelector}">
            <label>执行时间:</label>
            <input type="datetime-local" id="executeTimeInput" value="${State.executeTime}">
            <button id="pickButton">右键选择目标</button>
            <button id="startButton">开始</button>
            <button id="stopButton" disabled>停止</button>
            <div id="statusText">状态: 未运行 | 点击次数: 0</div>
        `;
        document.body.appendChild(controlPanel);

        // 绑定事件
        document.getElementById('pickButton').addEventListener('click', enableElementPicker);
        document.getElementById('startButton').addEventListener('click', startClicking);
        document.getElementById('stopButton').addEventListener('click', stopClicking);
        document.getElementById('targetSelectorInput').addEventListener('input', (event) => {
            State.targetSelector = event.target.value.trim();
            GM_setValue('targetSelector', State.targetSelector);
        });
        document.getElementById('executeTimeInput').addEventListener('change', (event) => {
            State.executeTime = event.target.value.trim();
            GM_setValue('executeTime', State.executeTime);
        });
    }

    // 更新状态文本
    function updateStatus(message) {
        const statusText = document.getElementById('statusText');
        statusText.innerText = `状态: ${message} | 点击次数: ${State.clickCount}`;
    }

    // 启用目标选择
    function enableElementPicker() {
        alert('请右键单击页面上的目标元素来选择它。');
        State.isPicking = true;

        document.addEventListener('mouseover', highlightElement, true);
        document.addEventListener('contextmenu', selectElement, true);
    }

    // 停用目标选择
    function disableElementPicker() {
        State.isPicking = false;
        const overlay = document.getElementById(CONFIG.OVERLAY_ID);
        overlay.style.display = 'none';

        document.removeEventListener('mouseover', highlightElement, true);
        document.removeEventListener('contextmenu', selectElement, true);
    }

    // 高亮鼠标悬停的元素
    function highlightElement(event) {
        if (!State.isPicking) return;

        const overlay = document.getElementById(CONFIG.OVERLAY_ID);
        const target = event.target;

        if (!target) return;
        const rect = target.getBoundingClientRect();
        overlay.style.display = 'block';
        overlay.style.top = `${rect.top + window.scrollY}px`;
        overlay.style.left = `${rect.left + window.scrollX}px`;
        overlay.style.width = `${rect.width}px`;
        overlay.style.height = `${rect.height}px`;
        debugLog('Highlighting element:', target);
    }

    // 选择目标元素
    function selectElement(event) {
        if (!State.isPicking) return;

        event.preventDefault();
        const target = event.target;

        const selector = generateSelector(target);
        State.targetSelector = selector;
        GM_setValue('targetSelector', selector);

        document.getElementById('targetSelectorInput').value = selector;
        disableElementPicker();
        alert(`目标元素已选择: ${selector}`);
        debugLog('Selected element:', target, 'Generated selector:', selector);
    }

    // 自动生成 CSS 选择器
    function generateSelector(element) {
        if (!element) return null;

        let selector = element.tagName.toLowerCase();
        if (element.id) {
            selector += `#${element.id}`;
        } else if (element.className) {
            const className = element.className.trim().split(/\s+/).join('.');
            selector += `.${className}`;
        }
        return selector;
    }

    // 开始点击
    function startClicking() {
        if (State.isRunning) return;

        const executeTime = new Date(State.executeTime).getTime();
        const now = Date.now();

        if (!State.targetSelector) {
            alert('请设置目标选择器!');
            return;
        }

        if (!executeTime || executeTime <= now) {
            alert('请设置一个未来的执行时间!');
            return;
        }

        const delay = executeTime - now;
        updateStatus(`等待 ${Math.ceil(delay / 1000)} 秒后执行`);
        debugLog('Scheduled to start in:', delay, 'ms');

        State.timer = setTimeout(() => {
            State.isRunning = true;
            State.clickCount = 0;
            executeClicks();
        }, delay);

        document.getElementById('stopButton').disabled = false;
    }

    // 停止点击
    function stopClicking() {
        if (State.timer) clearTimeout(State.timer);
        State.isRunning = false;
        updateStatus('已停止');
        document.getElementById('stopButton').disabled = true;
        debugLog('Stopped clicking.');
    }

    // 执行点击
    async function executeClicks() {
        const elements = document.querySelectorAll(State.targetSelector);
        if (elements.length === 0) {
            alert('未找到目标元素,点击操作终止!');
            stopClicking();
            return;
        }

        while (State.isRunning && State.clickCount < CONFIG.MAX_CLICKS) {
            for (const element of elements) {
                if (!State.isRunning) break;
                element.click();
                State.clickCount++;
                updateStatus('运行中');
                debugLog('Clicked element:', element, `Count: ${State.clickCount}`);
                await new Promise((resolve) => setTimeout(resolve, CONFIG.CLICK_INTERVAL));
            }
        }

        stopClicking();
        alert('点击操作完成!');
    }

    // 创建高亮层
    function createOverlay() {
        if (document.getElementById(CONFIG.OVERLAY_ID)) return;

        const overlay = document.createElement('div');
        overlay.id = CONFIG.OVERLAY_ID;
        document.body.appendChild(overlay);
    }

    function initialize() {
        addStyles();
        createControlPanel();
        createOverlay();
    }

    initialize();
})();