自动点击助手

可以用鼠标选择元素,设置自动点击网页按钮的脚本

您需要先安装一个扩展,例如 篡改猴Greasemonkey暴力猴,之后才能安装此脚本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安装一个扩展,例如 篡改猴暴力猴,之后才能安装此脚本。

您需要先安装一个扩展,例如 篡改猴Userscripts ,之后才能安装此脚本。

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

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

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

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

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

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

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

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

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

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

// ==UserScript==
// @name         自动点击助手
// @namespace    http://tampermonkey.net/
// @version      1.0
// @description  可以用鼠标选择元素,设置自动点击网页按钮的脚本
// @author       [email protected]
// @match        *://*/*
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_deleteValue
// ==/UserScript==

(function() {
    'use strict';

    // 配置存储键名
    const STORAGE_KEY = 'auto_click_tasks';
    
    // 全局变量
    let isSelecting = false;
    let selectedElement = null;
    let tasks = [];
    let activeIntervals = [];
    let overlay = null;
    let controlPanel = null;

    // 初始化
    function init() {
        loadTasks();
        createControlPanel();
        startSavedTasks();
    }

    // 加载保存的任务
    function loadTasks() {
        const savedTasks = GM_getValue(STORAGE_KEY, '[]');
        try {
            tasks = JSON.parse(savedTasks);
        } catch (e) {
            tasks = [];
        }
    }

    // 保存任务
    function saveTasks() {
        GM_setValue(STORAGE_KEY, JSON.stringify(tasks));
    }

    // 创建控制面板
    function createControlPanel() {
        controlPanel = document.createElement('div');
        controlPanel.id = 'auto-click-panel';
        controlPanel.style.cssText = `
            position: fixed;
            top: 20px;
            right: 20px;
            width: 300px;
            background: #fff;
            border: 2px solid #007bff;
            border-radius: 8px;
            box-shadow: 0 4px 12px rgba(0,0,0,0.15);
            z-index: 10000;
            font-family: Arial, sans-serif;
            font-size: 14px;
        `;
        controlPanel.innerHTML = `
                <div style="
                    background: #007bff;
                    color: white;
                    padding: 10px;
                    border-radius: 6px 6px 0 0;
                    font-weight: bold;
                    cursor: move;
                    user-select: none;
                " id="panel-header">
                    🖱️ 自动点击助手
                    <span style="float: right; cursor: pointer;" id="toggle-panel">−</span>
                </div>
                <div id="panel-content" style="padding: 15px;">
                    <div style="margin-bottom: 15px;">
                        <button id="select-element" style="
                            background: #28a745;
                            color: white;
                            border: none;
                            padding: 8px 16px;
                            border-radius: 4px;
                            cursor: pointer;
                            width: 100%;
                            margin-bottom: 10px;
                        ">选择元素</button>
                        
                        <div style="margin-bottom: 10px;">
                            <label>点击间隔(秒):</label>
                            <input type="number" id="interval-input" value="5" min="1" style="
                                width: 60px;
                                padding: 4px;
                                border: 1px solid #ddd;
                                border-radius: 4px;
                                margin-left: 10px;
                            ">
                        </div>
                        
                        <div style="margin-bottom: 10px;">
                            <label>任务名称:</label>
                            <input type="text" id="task-name" placeholder="例如: 刷新按钮" style="
                                width: 100%;
                                padding: 6px;
                                border: 1px solid #ddd;
                                border-radius: 4px;
                                margin-top: 5px;
                            ">
                        </div>
                        
                        <button id="add-task" style="
                            background: #007bff;
                            color: white;
                            border: none;
                            padding: 8px 16px;
                            border-radius: 4px;
                            cursor: pointer;
                            width: 100%;
                        ">添加任务</button>
                    </div>
                    
                    <div id="task-list" style="
                        max-height: 200px;
                        overflow-y: auto;
                        border-top: 1px solid #eee;
                        padding-top: 10px;
                    "></div>
                </div>
        `;
        
        document.body.appendChild(controlPanel);
        
        // 绑定事件
        bindPanelEvents();
        
        // 使面板可拖拽
        makeDraggable();
        
        // 更新任务列表显示
        updateTaskList();
    }

    // 绑定面板事件
    function bindPanelEvents() {
        // 选择元素按钮
        document.getElementById('select-element').addEventListener('click', startElementSelection);
        
        // 添加任务按钮
        document.getElementById('add-task').addEventListener('click', addTask);
        
        // 折叠/展开面板
        document.getElementById('toggle-panel').addEventListener('click', togglePanel);
    }

    // 使面板可拖拽
    function makeDraggable() {
        const header = document.getElementById('panel-header');
        let isDragging = false;
        let startX, startY, startLeft, startTop;
        
        function dragStart(e) {
            if (e.target.id === 'toggle-panel') return;
            
            isDragging = true;
            
            // 记录鼠标按下时的位置
            startX = e.clientX;
            startY = e.clientY;
            
            // 记录面板当前位置
            const rect = controlPanel.getBoundingClientRect();
            startLeft = rect.left;
            startTop = rect.top;
            
            e.preventDefault();
            e.stopPropagation();
            
            document.addEventListener('mousemove', drag);
            document.addEventListener('mouseup', dragEnd);
        }
        
        function drag(e) {
            if (!isDragging) return;
            
            e.preventDefault();
            e.stopPropagation();
            
            // 计算鼠标移动的距离
            const deltaX = e.clientX - startX;
            const deltaY = e.clientY - startY;
            
            // 计算新位置
            let newLeft = startLeft + deltaX;
            let newTop = startTop + deltaY;

            // 确保面板不会被拖出视窗
            newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - controlPanel.offsetWidth));
            newTop = Math.max(0, Math.min(newTop, window.innerHeight - controlPanel.offsetHeight));

            // 更新面板位置
            controlPanel.style.left = `${newLeft}px`;
            controlPanel.style.top = `${newTop}px`;
            controlPanel.style.right = 'auto';
            controlPanel.style.bottom = 'auto';
        }
        
        function dragEnd(e) {
            isDragging = false;
            e.preventDefault();
            e.stopPropagation();
            
            document.removeEventListener('mousemove', drag);
            document.removeEventListener('mouseup', dragEnd);
        }
        
        header.addEventListener('mousedown', dragStart);
    }

    // 折叠/展开面板
    function togglePanel() {
        const content = document.getElementById('panel-content');
        const toggle = document.getElementById('toggle-panel');
        
        if (content.style.display === 'none') {
            content.style.display = 'block';
            toggle.textContent = '−';
        } else {
            content.style.display = 'none';
            toggle.textContent = '+';
        }
    }

    // 开始元素选择
    function startElementSelection() {
        if (isSelecting) {
            stopElementSelection();
            return;
        }
        
        isSelecting = true;
        document.getElementById('select-element').textContent = '取消选择';
        document.getElementById('select-element').style.background = '#dc3545';
        
        // 创建遮罩层
        createOverlay();
        
        // 添加鼠标事件监听
        document.addEventListener('mouseover', highlightElement);
        document.addEventListener('click', selectElement, true);
        
        // 显示提示
        showToast('请点击要自动点击的元素');
    }

    // 停止元素选择
    function stopElementSelection() {
        isSelecting = false;
        document.getElementById('select-element').textContent = '选择元素';
        document.getElementById('select-element').style.background = '#28a745';
        
        // 移除遮罩层
        if (overlay) {
            overlay.remove();
            overlay = null;
        }
        
        // 移除事件监听
        document.removeEventListener('mouseover', highlightElement);
        document.removeEventListener('click', selectElement, true);
        
        // 清除高亮
        clearHighlight();
    }

    // 创建遮罩层
    function createOverlay() {
        overlay = document.createElement('div');
        overlay.style.cssText = `
            position: fixed;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 123, 255, 0.1);
            z-index: 9999;
            pointer-events: none;
        `;
        document.body.appendChild(overlay);
    }

    // 高亮元素
    function highlightElement(e) {
        if (!isSelecting || e.target.closest('#auto-click-panel')) return;
        
        clearHighlight();
        e.target.style.outline = '3px solid #007bff';
        e.target.style.backgroundColor = 'rgba(0, 123, 255, 0.2)';
        e.target.setAttribute('data-highlighted', 'true');
    }

    // 清除高亮
    function clearHighlight() {
        const highlighted = document.querySelectorAll('[data-highlighted="true"]');
        highlighted.forEach(el => {
            el.style.outline = '';
            el.style.backgroundColor = '';
            el.removeAttribute('data-highlighted');
        });
    }

    // 选择元素
    function selectElement(e) {
        if (!isSelecting || e.target.closest('#auto-click-panel')) return;
        
        e.preventDefault();
        e.stopPropagation();
        e.stopImmediatePropagation();
        
        selectedElement = e.target;
        stopElementSelection();
        
        // 显示选中的元素信息
        const elementInfo = getElementInfo(selectedElement);
        showToast(`已选择: ${elementInfo}`);
        
        // 自动填充任务名称
        const taskNameInput = document.getElementById('task-name');
        if (!taskNameInput.value) {
            taskNameInput.value = elementInfo;
        }
    }

    // 获取元素信息
    function getElementInfo(element) {
        const tagName = element.tagName.toLowerCase();
        const text = element.textContent.trim().substring(0, 20);
        const id = element.id ? `#${element.id}` : '';
        const className = element.className ? `.${element.className.split(' ')[0]}` : '';
        
        return `${tagName}${id}${className}${text ? ` "${text}"` : ''}`;
    }

    // 添加任务
    function addTask() {
        if (!selectedElement) {
            showToast('请先选择一个元素', 'error');
            return;
        }
        
        const interval = parseInt(document.getElementById('interval-input').value);
        const taskName = document.getElementById('task-name').value.trim();
        
        if (!taskName) {
            showToast('请输入任务名称', 'error');
            return;
        }
        
        if (interval < 1) {
            showToast('点击间隔必须大于0秒', 'error');
            return;
        }
        
        // 生成元素选择器
        const selector = generateSelector(selectedElement);
        
        const task = {
            id: Date.now(),
            name: taskName,
            selector: selector,
            interval: interval,
            url: window.location.href,
            domain: window.location.hostname,
            active: false,
            created: new Date().toLocaleString()
        };
        
        tasks.push(task);
        saveTasks();
        updateTaskList();
        
        // 清空输入
        document.getElementById('task-name').value = '';
        selectedElement = null;
        
        showToast(`任务 "${taskName}" 已添加`);
    }

    // 生成元素选择器
    function generateSelector(element) {
        // 优先使用ID
        if (element.id) {
            return `#${element.id}`;
        }

         // 使用标签名和属性
        let selector = element.tagName.toLowerCase();

        // 使用类名
        if (element.className) {
            const classes = element.className.split(' ').filter(c=>c.indexOf(':') === -1).filter(c => c.trim());
            for (const cla of classes) {
                selector+= `.${cla}`;
            }
        }



        // 添加属性选择器
        const attrs = ['data-id', 'data-action', 'name', 'type'];
        for (const attr of attrs) {
            if (element.hasAttribute(attr)) {
                selector += `[${attr}="${element.getAttribute(attr)}"]`;
                break;
            }
        }

        return selector;
    }


    // 更新任务列表
    function updateTaskList() {
        const taskList = document.getElementById('task-list');
        
        if (tasks.length === 0) {
            taskList.innerHTML = '<div style="color: #666; text-align: center; padding: 20px;">暂无任务</div>';
            return;
        }
        
        const currentDomain = window.location.hostname;
        const relevantTasks = tasks.filter(task => task.domain === currentDomain);
        
        if (relevantTasks.length === 0) {
            taskList.innerHTML = '<div style="color: #666; text-align: center; padding: 20px;">当前域名无任务</div>';
            return;
        }
        
        taskList.innerHTML = '';
        relevantTasks.forEach(task => {
            const taskDiv = document.createElement('div');
            taskDiv.style.cssText = `
                border: 1px solid #ddd;
                border-radius: 4px;
                padding: 10px;
                margin-bottom: 10px;
                background: ${task.active ? '#e8f5e8' : '#f8f9fa'};
            `;
            
            taskDiv.innerHTML = `
                <div style="font-weight: bold; margin-bottom: 5px;">${task.name}</div>
                <div style="font-size: 12px; color: #666; margin-bottom: 8px;">
                    间隔: ${task.interval}秒 | 创建: ${task.created}
                </div>
                <div style="display: flex; gap: 5px;">
                    <button class="toggle-btn" style="
                        background: ${task.active ? '#dc3545' : '#28a745'};
                        color: white;
                        border: none;
                        padding: 4px 8px;
                        border-radius: 3px;
                        cursor: pointer;
                        font-size: 12px;
                    ">
                        ${task.active ? '停止' : '启动'}
                    </button>
                    <button class="delete-btn" style="
                        background: #6c757d;
                        color: white;
                        border: none;
                        padding: 4px 8px;
                        border-radius: 3px;
                        cursor: pointer;
                        font-size: 12px;
                    ">
                        删除
                    </button>
                </div>
            `;
            
            // 绑定事件
            const toggleBtn = taskDiv.querySelector('.toggle-btn');
            const deleteBtn = taskDiv.querySelector('.delete-btn');
            
            toggleBtn.addEventListener('click', () => toggleTask(task.id));
            deleteBtn.addEventListener('click', () => deleteTask(task.id));
            
            taskList.appendChild(taskDiv);
        });
    }

    // 切换任务状态
    function toggleTask(taskId) {
        const task = tasks.find(t => t.id === taskId);
        if (!task) return;
        
        if (task.active) {
            stopTask(taskId);
        } else {
            startTask(taskId);
        }
    }
    
    // 暴露到全局
    window.toggleTask = toggleTask;

    // 启动任务
    function startTask(taskId) {
        const task = tasks.find(t => t.id === taskId);
        if (!task) return;
        
        const element = document.querySelector(task.selector);
        if (!element) {
            showToast(`找不到元素: ${task.selector}`, 'error');
            return;
        }
        
        task.active = true;
        const intervalId = setInterval(() => {
            const currentElement = document.querySelector(task.selector);
            if (currentElement) {
                currentElement.click();
                console.log(`自动点击: ${task.name}`);
            } else {
                console.warn(`元素不存在,停止任务: ${task.name}`);
                stopTask(taskId);
            }
        }, task.interval * 1000);
        
        activeIntervals.push({ taskId, intervalId });
        saveTasks();
        updateTaskList();
        
        showToast(`任务 "${task.name}" 已启动`);
    }

    // 停止任务
    function stopTask(taskId) {
        const task = tasks.find(t => t.id === taskId);
        if (!task) return;
        
        task.active = false;
        const intervalIndex = activeIntervals.findIndex(item => item.taskId === taskId);
        
        if (intervalIndex !== -1) {
            clearInterval(activeIntervals[intervalIndex].intervalId);
            activeIntervals.splice(intervalIndex, 1);
        }
        
        saveTasks();
        updateTaskList();
        
        showToast(`任务 "${task.name}" 已停止`);
    }

    // 删除任务
    function deleteTask(taskId) {
        if (!confirm('确定要删除这个任务吗?')) return;
        
        stopTask(taskId);
        tasks = tasks.filter(t => t.id !== taskId);
        saveTasks();
        updateTaskList();
        
        showToast('任务已删除');
    }
    
    // 暴露到全局
    window.deleteTask = deleteTask;

    // 启动保存的任务
    function startSavedTasks() {
        const currentDomain = window.location.hostname;
        const relevantTasks = tasks.filter(task => 
            task.domain === currentDomain && task.active
        );
        
        relevantTasks.forEach(task => {
            // 延迟启动,确保页面加载完成
            setTimeout(() => {
                const element = document.querySelector(task.selector);
                if (element) {
                    startTask(task.id);
                } else {
                    console.warn(`页面加载后找不到元素,任务未启动: ${task.name}`);
                    task.active = false;
                    saveTasks();
                }
            }, 2000);
        });
    }

    // 显示提示消息
    function showToast(message, type = 'info') {
        const toast = document.createElement('div');
        toast.style.cssText = `
            position: fixed;
            top: 50px;
            right: 20px;
            background: ${type === 'error' ? '#dc3545' : '#28a745'};
            color: white;
            padding: 12px 20px;
            border-radius: 4px;
            z-index: 10001;
            font-family: Arial, sans-serif;
            font-size: 14px;
            box-shadow: 0 2px 8px rgba(0,0,0,0.2);
        `;
        toast.textContent = message;
        
        document.body.appendChild(toast);
        
        setTimeout(() => {
            toast.remove();
        }, 3000);
    }

    // 页面加载完成后初始化
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();