// ==UserScript==
// @name 智能自动点击器 (iOS极简版 v1.2)
// @namespace http://tampermonkey.net/
// @version 1.2.0
// @description iOS风格UI,支持悬浮球自由拖拽、坐标记忆及自定义快捷键
// @author You
// @match *://*/*
// @grant none
// @run-at document-end
// @downloadURL https://update.greasyfork.icu/scripts/558927/%E6%99%BA%E8%83%BD%E8%87%AA%E5%8A%A8%E7%82%B9%E5%87%BB%E5%99%A8%20%28iOS%E6%9E%81%E7%AE%80%E7%89%88%20v12%29.user.js
// @updateURL https://update.greasyfork.icu/scripts/558927/%E6%99%BA%E8%83%BD%E8%87%AA%E5%8A%A8%E7%82%B9%E5%87%BB%E5%99%A8%20%28iOS%E6%9E%81%E7%AE%80%E7%89%88%20v12%29.meta.js
// ==/UserScript==
(function() {
'use strict';
// 注入增强版 iOS 风格 CSS
const style = document.createElement('style');
style.innerHTML = `
@supports (-webkit-backdrop-filter: none) or (backdrop-filter: none) {
.ios-glass {
background: rgba(255, 255, 255, 0.75) !important;
-webkit-backdrop-filter: saturate(180%) blur(20px) !important;
backdrop-filter: saturate(180%) blur(20px) !important;
}
}
.ios-glass {
background: rgba(255, 255, 255, 0.95);
border: 1px solid rgba(0, 0, 0, 0.1);
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.15);
}
.auto-clicker-fab {
position: fixed;
width: 44px;
height: 44px;
border-radius: 22px;
z-index: 999998;
cursor: move;
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
transition: transform 0.2s cubic-bezier(0.2, 0, 0.2, 1), box-shadow 0.2s;
user-select: none;
touch-action: none;
}
.auto-clicker-fab:active { transform: scale(0.9); }
.auto-clicker-panel {
position: fixed;
z-index: 999997;
border-radius: 16px;
padding: 20px;
display: none;
width: 280px;
font-family: -apple-system, BlinkMacSystemFont, "SF Pro Text", sans-serif;
color: #1d1d1f;
}
.ios-title { font-size: 17px; font-weight: 600; margin: 0 0 16px 0; text-align: center; }
.ios-input-group { margin-bottom: 12px; }
.ios-label { display: block; font-size: 12px; font-weight: 500; color: #86868b; margin-bottom: 6px; text-transform: uppercase; }
.ios-input { width: 100%; box-sizing: border-box; padding: 10px 12px; background: rgba(0, 0, 0, 0.05); border: none; border-radius: 10px; font-size: 14px; color: #1d1d1f; outline: none; }
.ios-shortcut-btn { background: rgba(0, 113, 227, 0.1); color: #0071e3; font-weight: 600; text-align: center; cursor: pointer; padding: 8px; border-radius: 8px; font-size: 13px; }
.ios-btn { width: 100%; padding: 12px; border: none; border-radius: 12px; font-size: 15px; font-weight: 600; cursor: pointer; transition: all 0.2s; margin-bottom: 8px; }
.ios-btn-primary { background: #0071e3; color: white; }
.ios-btn-success { background: #34c759; color: white; }
.ios-btn-danger { background: #ff3b30; color: white; }
.ios-btn-disabled { background: #e5e5ea; color: #8e8e93; cursor: not-allowed; }
.ios-flex-row { display: flex; gap: 8px; }
`;
document.head.appendChild(style);
// 配置初始化
const config = {
enabled: false,
delay: 1000,
clickCount: 0,
currentClicks: 0,
targetX: 0,
targetY: 0,
hasTarget: false,
shortcut: { ctrl: true, shift: true, key: 'A', display: 'Ctrl + Shift + A' },
fabPos: { top: '20px', left: 'auto', right: '20px' }
};
// 加载本地配置
const savedConfig = localStorage.getItem('auto_clicker_v12_config');
if (savedConfig) Object.assign(config, JSON.parse(savedConfig));
// 创建元素
const cursor = document.createElement('div');
cursor.style.cssText = `position: fixed; width: 30px; height: 30px; border: 2px solid #0071e3; border-radius: 50%; pointer-events: none; z-index: 999999; display: none; background: rgba(0, 113, 227, 0.1); transform: translate(-50%, -50%); transition: transform 0.1s;`;
const mainButton = document.createElement('div');
mainButton.className = 'auto-clicker-fab ios-glass';
mainButton.innerHTML = '⚙️';
Object.assign(mainButton.style, config.fabPos);
const panel = document.createElement('div');
panel.className = 'auto-clicker-panel ios-glass';
// 面板跟随悬浮球位置逻辑
const updatePanelPos = () => {
const rect = mainButton.getBoundingClientRect();
panel.style.top = (rect.bottom + 10) + 'px';
panel.style.left = (rect.right - 280) + 'px';
};
panel.innerHTML = `
点击器设置
`;
document.body.append(cursor, mainButton, panel);
// 拖拽逻辑
let isDragging = false, dragX, dragY;
mainButton.addEventListener('mousedown', (e) => {
isDragging = true;
dragX = e.clientX - mainButton.offsetLeft;
dragY = e.clientY - mainButton.offsetTop;
mainButton.style.transition = 'none';
});
document.addEventListener('mousemove', (e) => {
if (!isDragging) return;
let x = e.clientX - dragX, y = e.clientY - dragY;
mainButton.style.left = x + 'px';
mainButton.style.top = y + 'px';
mainButton.style.right = 'auto';
if (panel.style.display === 'block') updatePanelPos();
});
document.addEventListener('mouseup', () => {
if (!isDragging) return;
isDragging = false;
mainButton.style.transition = 'transform 0.2s';
config.fabPos = { top: mainButton.style.top, left: mainButton.style.left, right: 'auto' };
saveConfig();
});
// 快捷键录制
let isRecording = false;
const shortcutBtn = document.getElementById('shortcut-display');
shortcutBtn.addEventListener('click', () => {
isRecording = true;
shortcutBtn.innerText = '请按下按键...';
shortcutBtn.style.background = '#ff9500';
shortcutBtn.style.color = 'white';
});
document.addEventListener('keydown', (e) => {
if (isRecording) {
e.preventDefault();
const keys = [];
if (e.ctrlKey) keys.push('Ctrl');
if (e.shiftKey) keys.push('Shift');
if (e.altKey) keys.push('Alt');
if (!['Control', 'Shift', 'Alt'].includes(e.key)) keys.push(e.key.toUpperCase());
config.shortcut = {
ctrl: e.ctrlKey, shift: e.shiftKey, alt: e.altKey,
key: e.key.toUpperCase(),
display: keys.join(' + ')
};
shortcutBtn.innerText = config.shortcut.display;
shortcutBtn.style = '';
isRecording = false;
saveConfig();
return;
}
// 匹配快捷键启动/停止
const s = config.shortcut;
if (e.ctrlKey === s.ctrl && e.shiftKey === s.shift && e.altKey === s.alt && e.key.toUpperCase() === s.key) {
e.preventDefault();
config.enabled ? stopClicking() : startClicking();
}
});
// 核心功能逻辑
function saveConfig() { localStorage.setItem('auto_clicker_v12_config', JSON.stringify(config)); }
mainButton.addEventListener('click', () => {
const isVisible = panel.style.display === 'block';
panel.style.display = isVisible ? 'none' : 'block';
if (!isVisible) updatePanelPos();
});
const setPosBtn = document.getElementById('set-position-btn');
const startBtn = document.getElementById('start-btn');
const stopBtn = document.getElementById('stop-btn');
let clickInterval = null;
setPosBtn.addEventListener('click', () => {
setPosBtn.innerText = '请点击目标...';
setPosBtn.style.background = '#ff9500';
cursor.style.display = 'block';
const handler = (e) => {
e.preventDefault(); e.stopPropagation();
config.targetX = e.clientX; config.targetY = e.clientY; config.hasTarget = true;
saveConfig();
document.removeEventListener('click', handler, true);
cursor.style.display = 'none';
setPosBtn.innerText = '📍 重新设置位置';
setPosBtn.style.background = '';
};
document.addEventListener('click', handler, true);
});
function performClick() {
if (config.clickCount > 0 && config.currentClicks >= config.clickCount) return stopClicking();
const el = document.elementFromPoint(config.targetX, config.targetY);
if (el) {
const init = { view: window, bubbles: true, cancelable: true, clientX: config.targetX, clientY: config.targetY, button: 0 };
['mousedown', 'mouseup', 'click'].forEach(t => el.dispatchEvent(new MouseEvent(t, init)));
}
config.currentClicks++;
document.getElementById('click-counter') && (document.getElementById('click-counter').innerText = config.currentClicks);
}
function startClicking() {
if (!config.hasTarget) return alert('请先设置位置');
config.enabled = true; config.currentClicks = 0;
startBtn.disabled = true; startBtn.className = 'ios-btn ios-btn-disabled';
stopBtn.disabled = false; stopBtn.className = 'ios-btn ios-btn-danger';
mainButton.innerHTML = '🔴';
clickInterval = setInterval(performClick, config.delay);
}
function stopClicking() {
config.enabled = false; clearInterval(clickInterval);
startBtn.disabled = false; startBtn.className = 'ios-btn ios-btn-primary';
stopBtn.disabled = true; stopBtn.className = 'ios-btn ios-btn-disabled';
mainButton.innerHTML = '⚙️';
}
startBtn.addEventListener('click', startClicking);
stopBtn.addEventListener('click', stopClicking);
document.getElementById('click-delay').addEventListener('change', (e) => { config.delay = e.target.value; saveConfig(); });
document.getElementById('click-count').addEventListener('change', (e) => { config.clickCount = e.target.value; saveConfig(); });
})();