// ==UserScript==
// @name 悬浮球后台打开(修复版)
// @namespace http://tampermonkey.net/
// @version 2.1
// @description 点击悬浮球开关后台模式,点一下开启,再点关闭
// @author You
// @match *://*/*
// @grant none
// @downloadURL https://update.greasyfork.icu/scripts/575946/%E6%82%AC%E6%B5%AE%E7%90%83%E5%90%8E%E5%8F%B0%E6%89%93%E5%BC%80%EF%BC%88%E4%BF%AE%E5%A4%8D%E7%89%88%EF%BC%89.user.js
// @updateURL https://update.greasyfork.icu/scripts/575946/%E6%82%AC%E6%B5%AE%E7%90%83%E5%90%8E%E5%8F%B0%E6%89%93%E5%BC%80%EF%BC%88%E4%BF%AE%E5%A4%8D%E7%89%88%EF%BC%89.meta.js
// ==/UserScript==
(function() {
'use strict';
// ========== 配置 ==========
let bgMode = false; // 后台模式开关
let touchStartTime = 0; // 触摸开始时间
let touchMoved = false; // 是否移动过
let startX, startY;
// ========== 创建悬浮球 ==========
const ball = document.createElement('div');
ball.id = 'bgOpenBall';
ball.innerHTML = `
后台
模式
`;
ball.style.cssText = `
position: fixed;
width: 54px;
height: 54px;
z-index: 99999;
cursor: pointer;
touch-action: none;
`;
document.body.appendChild(ball);
const ballInner = document.getElementById('ballInner');
// 读取上次保存的位置
try {
const savedLeft = localStorage.getItem('bgBallLeft');
const savedTop = localStorage.getItem('bgBallTop');
if (savedLeft && savedTop && savedLeft !== 'null' && savedTop !== 'null') {
ball.style.left = savedLeft;
ball.style.top = savedTop;
ball.style.right = 'auto';
ball.style.bottom = 'auto';
} else {
// 默认右下角
ball.style.right = '20px';
ball.style.bottom = '100px';
}
} catch(e) {}
// ========== 更新悬浮球外观 ==========
function updateBallAppearance() {
if (bgMode) {
ballInner.style.background = '#e53935';
ballInner.innerHTML = '后台
✓开启';
} else {
ballInner.style.background = '#3a3a3a';
ballInner.innerHTML = '后台
模式';
}
}
// ========== 切换后台模式 ==========
function toggleMode() {
bgMode = !bgMode;
updateBallAppearance();
if (bgMode) {
showToast('✅ 后台模式已开启,点击链接自动后台打开');
} else {
showToast('❌ 后台模式已关闭,链接正常打开');
}
}
// ========== 提示浮层 ==========
let activeToast = null;
function showToast(msg) {
if (activeToast) activeToast.remove();
const toast = document.createElement('div');
toast.textContent = msg;
toast.style.cssText = `
position: fixed;
bottom: 170px;
left: 50%;
transform: translateX(-50%);
background: rgba(0,0,0,0.85);
color: #fff;
padding: 10px 18px;
border-radius: 30px;
font-size: 14px;
z-index: 100000;
white-space: nowrap;
pointer-events: none;
font-family: system-ui, -apple-system, sans-serif;
box-shadow: 0 2px 10px rgba(0,0,0,0.3);
`;
document.body.appendChild(toast);
activeToast = toast;
setTimeout(() => {
if (toast && toast.remove) toast.remove();
if (activeToast === toast) activeToast = null;
}, 1500);
}
// ========== 拖动逻辑 ==========
let currentLeft = 0, currentTop = 0;
let isDragging = false;
ball.addEventListener('touchstart', function(e) {
e.preventDefault();
const touch = e.touches[0];
// 获取当前位置
const leftVal = ball.style.left;
const rightVal = ball.style.right;
if (leftVal && leftVal !== 'auto') {
currentLeft = parseFloat(leftVal);
} else if (rightVal && rightVal !== 'auto') {
currentLeft = window.innerWidth - ball.offsetWidth - parseFloat(rightVal);
} else {
currentLeft = window.innerWidth - ball.offsetWidth - 20;
}
currentTop = parseFloat(ball.style.top);
if (isNaN(currentTop)) currentTop = window.innerHeight - ball.offsetHeight - 100;
startX = touch.clientX - currentLeft;
startY = touch.clientY - currentTop;
touchStartTime = Date.now();
touchMoved = false;
isDragging = false;
});
ball.addEventListener('touchmove', function(e) {
e.preventDefault();
const touch = e.touches[0];
let newLeft = touch.clientX - startX;
let newTop = touch.clientY - startY;
// 如果移动距离超过5px,认为是拖动
const moveDist = Math.abs(newLeft - currentLeft) + Math.abs(newTop - currentTop);
if (moveDist > 5) {
touchMoved = true;
isDragging = true;
}
// 边界限制
newLeft = Math.max(0, Math.min(window.innerWidth - ball.offsetWidth, newLeft));
newTop = Math.max(0, Math.min(window.innerHeight - ball.offsetHeight, newTop));
ball.style.left = newLeft + 'px';
ball.style.top = newTop + 'px';
ball.style.right = 'auto';
ball.style.bottom = 'auto';
currentLeft = newLeft;
currentTop = newTop;
});
ball.addEventListener('touchend', function(e) {
e.preventDefault();
const touchDuration = Date.now() - touchStartTime;
// 保存位置
try {
localStorage.setItem('bgBallLeft', ball.style.left);
localStorage.setItem('bgBallTop', ball.style.top);
} catch(e) {}
// 如果没有移动且触摸时间小于300ms,认为是点击
if (!touchMoved && touchDuration < 300) {
toggleMode();
}
touchMoved = false;
isDragging = false;
});
// ========== 拦截链接点击,实现后台打开 ==========
document.addEventListener('click', function(e) {
if (!bgMode) return; // 后台模式未开启,不拦截
// 如果点的是悬浮球本身,不拦截(让toggleMode处理)
if (ball.contains(e.target)) return;
const link = e.target.closest('a');
if (!link) return;
if (!link.href || link.href === '') return;
if (link.href.startsWith('javascript:')) return;
// 后台打开
e.preventDefault();
e.stopPropagation();
const newTab = window.open(link.href, '_blank');
if (newTab) {
newTab.blur();
window.focus();
}
// 震动反馈
if (navigator.vibrate) navigator.vibrate(30);
// 可选:显示简短提示
// showToast('🔗 已后台打开');
}, true); // 使用捕获阶段
// 初始化外观
updateBallAppearance();
showToast('✨ 悬浮球已加载,点击开启后台模式');
})();