// ==UserScript== // @name 网页定时刷新 // @namespace http://tampermonkey.net/ // @version 1.0 // @description 网页定时刷新工具 // @author huihuia24 // @match *://*/* // @grant GM_setValue // @grant GM_getValue // @noframes // @homepage https://github.com/huihuia24 // @source https://github.com/huihuia24/Web-page-auto-refresh // @icon https://pic.uzzf.com/up/2025-5/2025591617247637.png // @downloadURL none // ==/UserScript== (function() { 'use strict'; // 单实例防护 const UI_ID = 'fullDragRefreshTool'; if (document.getElementById(UI_ID)) return; const SITE_KEY = window.location.hostname; const INSTANCE_KEY = `${SITE_KEY}_refresh_instance`; if (GM_getValue(INSTANCE_KEY, false)) return; GM_setValue(INSTANCE_KEY, true); // 状态存储 const STATE_KEY = { isEnabled: `${SITE_KEY}_is_enabled`, interval: `${SITE_KEY}_interval`, unit: `${SITE_KEY}_unit`, lastStartTime: `${SITE_KEY}_last_start`, position: `${SITE_KEY}_ui_position` }; // 恢复状态 let isEnabled = GM_getValue(STATE_KEY.isEnabled, false); let currentUnit = GM_getValue(STATE_KEY.unit, 's'); let intervalSeconds = GM_getValue(STATE_KEY.interval, 60); let lastStartTime = GM_getValue(STATE_KEY.lastStartTime, Date.now()); let remainingSeconds = 0; let timer = null; let isDragging = false; let offsetX, offsetY; // 计算剩余时间 function calculateRemaining() { if (!isEnabled) return intervalSeconds; const now = Date.now(); const elapsed = Math.floor((now - lastStartTime) / 1000); return Math.max(0, intervalSeconds - elapsed); } remainingSeconds = calculateRemaining(); // 单位转换 function convertToSeconds(value, unit) { switch(unit) { case 'h': return value * 3600; case 'm': return value * 60; case 's': default: return value; } } function convertFromSeconds(seconds, unit) { switch(unit) { case 'h': return Math.floor(seconds / 3600); case 'm': return Math.floor(seconds / 60); case 's': default: return seconds; } } function formatTime(seconds) { if (seconds < 60) return `${seconds}s`; const m = Math.floor(seconds / 60); const s = seconds % 60; return `${m}m${s}s`; } // 创建全屏拖拽UI(交互优化版) function createUI() { // 主容器(整个区域可拖拽) const container = document.createElement('div'); container.id = UI_ID; container.style.cssText = ` position: fixed; background: white; border: 1px solid #e2e8f0; border-radius: 12px; padding: 12px 16px; box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08); z-index: 99999; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; font-size: 14px; display: flex; align-items: center; gap: 12px; user-select: none; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); cursor: default; /* 保持默认指针样式 */ `; // 恢复位置 const savedPos = GM_getValue(STATE_KEY.position, { top: '20px', left: '20px' }); container.style.top = savedPos.top; container.style.left = savedPos.left; // 图标区域(视觉强化) const iconArea = document.createElement('div'); iconArea.style.cssText = ` width: 32px; height: 32px; border-radius: 8px; background: linear-gradient(135deg, #6366f1, #8b5cf6); display: flex; align-items: center; justify-content: center; transition: all 0.2s ease; `; iconArea.innerHTML = ` `; // 标题 const title = document.createElement('span'); title.textContent = '定时刷新 ='; title.style.fontWeight = '500'; title.style.color = '#1e293b'; // 输入框(现代风格) const input = document.createElement('input'); input.type = 'number'; input.value = convertFromSeconds(intervalSeconds, currentUnit); input.min = currentUnit === 's' ? 5 : 1; input.style.cssText = ` width: 50px; padding: 6px 10px; border: 1px solid #e2e8f0; border-radius: 8px; font-size: 14px; outline: none; transition: border-color 0.2s ease; `; input.addEventListener('focus', () => { input.style.borderColor = '#a5b4fc'; }); input.addEventListener('blur', () => { input.style.borderColor = '#e2e8f0'; }); // 单位选择(下拉增强) const unitSelect = document.createElement('select'); unitSelect.style.cssText = ` padding: 6px 10px; border: 1px solid #e2e8f0; border-radius: 8px; background: white; font-size: 14px; color: #475569; cursor: pointer; outline: none; appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%2394a3b8' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' width='12' height='12'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 10px center; background-size: 12px; transition: border-color 0.2s ease; `; ['s', 'm', 'h'].forEach(unit => { const option = document.createElement('option'); option.value = unit; option.textContent = { s: '秒', m: '分', h: '时' }[unit]; option.selected = unit === currentUnit; unitSelect.appendChild(option); }); unitSelect.addEventListener('focus', () => { unitSelect.style.borderColor = '#a5b4fc'; }); unitSelect.addEventListener('blur', () => { unitSelect.style.borderColor = '#e2e8f0'; }); // 立体控制按钮(渐变+悬停动画) const controlBtn = document.createElement('button'); controlBtn.style.cssText = ` display: flex; align-items: center; gap: 6px; padding: 8px 16px; border: none; border-radius: 8px; color: white; cursor: pointer; font-size: 14px; font-weight: 500; background: ${isEnabled ? 'linear-gradient(135deg, #f87171, #ef4444)' : 'linear-gradient(135deg, #6366f1, #8b5cf6)'}; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); `; controlBtn.innerHTML = isEnabled ? ` 停止 ` : ` 启动 `; controlBtn.addEventListener('mouseenter', () => { controlBtn.style.transform = 'translateY(-2px)'; controlBtn.style.boxShadow = isEnabled ? '0 6px 12px rgba(239, 68, 68, 0.3)' : '0 6px 12px rgba(99, 102, 241, 0.3)'; }); controlBtn.addEventListener('mouseleave', () => { controlBtn.style.transform = 'translateY(0)'; controlBtn.style.boxShadow = isEnabled ? '0 4px 8px rgba(239, 68, 68, 0.1)' : '0 4px 8px rgba(99, 102, 241, 0.1)'; }); // 状态显示(动态变化) const statusText = document.createElement('span'); statusText.textContent = isEnabled ? `(剩余: ${formatTime(remainingSeconds)})` : '(已停止)'; statusText.style.cssText = ` color: #64748b; font-size: 13px; min-width: 90px; text-align: center; font-family: monospace; transition: all 0.3s ease; `; // 组装UI container.appendChild(iconArea); container.appendChild(title); container.appendChild(input); container.appendChild(unitSelect); container.appendChild(controlBtn); container.appendChild(statusText); document.body.appendChild(container); // 全屏拖拽功能实现(整个UI区域可拖拽) container.addEventListener('mousedown', (e) => { isDragging = true; const rect = container.getBoundingClientRect(); offsetX = e.clientX - rect.left; offsetY = e.clientY - rect.top; container.style.transition = 'none'; container.style.zIndex = '999999'; container.style.boxShadow = '0 8px 24px rgba(0, 0, 0, 0.15)'; e.preventDefault(); }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const newLeft = e.clientX - offsetX; const newTop = e.clientY - offsetY; const maxLeft = window.innerWidth - container.offsetWidth - 20; const maxTop = window.innerHeight - container.offsetHeight - 20; container.style.left = `${Math.max(20, Math.min(newLeft, maxLeft))}px`; container.style.top = `${Math.max(20, Math.min(newTop, maxTop))}px`; }); document.addEventListener('mouseup', () => { if (isDragging) { isDragging = false; container.style.transition = 'all 0.3s cubic-bezier(0.4, 0, 0.2, 1)'; container.style.zIndex = '99999'; container.style.boxShadow = '0 6px 18px rgba(0, 0, 0, 0.08)'; GM_setValue(STATE_KEY.position, { top: container.style.top, left: container.style.left }); } }); // 其他事件绑定 input.addEventListener('change', () => { const value = Math.max(parseInt(input.value, 10) || 1, input.min); intervalSeconds = convertToSeconds(value, currentUnit); GM_setValue(STATE_KEY.interval, intervalSeconds); if (isEnabled) { restartTimer(); } else { remainingSeconds = intervalSeconds; statusText.textContent = `(剩余: ${formatTime(remainingSeconds)})`; } }); unitSelect.addEventListener('change', () => { currentUnit = unitSelect.value; input.value = convertFromSeconds(intervalSeconds, currentUnit); input.min = currentUnit === 's' ? 5 : 1; GM_setValue(STATE_KEY.unit, currentUnit); if (isEnabled) { restartTimer(); } else { remainingSeconds = intervalSeconds; statusText.textContent = `(剩余: ${formatTime(remainingSeconds)})`; } }); controlBtn.addEventListener('click', () => { if (isEnabled) { stopTimer(); controlBtn.innerHTML = ` 启动 `; controlBtn.style.background = 'linear-gradient(135deg, #6366f1, #8b5cf6)'; statusText.textContent = '(已停止)'; } else { startTimer(); controlBtn.innerHTML = ` 停止 `; controlBtn.style.background = 'linear-gradient(135deg, #f87171, #ef4444)'; } }); return { container, controlBtn, statusText, input, unitSelect, iconArea }; } // 计时器控制 function startTimer() { isEnabled = true; lastStartTime = Date.now(); GM_setValue(STATE_KEY.isEnabled, true); GM_setValue(STATE_KEY.lastStartTime, lastStartTime); if (timer) clearInterval(timer); timer = setInterval(() => { remainingSeconds--; uiElements.statusText.textContent = `(剩余: ${formatTime(remainingSeconds)})`; if (remainingSeconds <= 0) { clearInterval(timer); GM_setValue(STATE_KEY.lastStartTime, Date.now()); window.location.reload(); } }, 1000); } function stopTimer() { if (timer) clearInterval(timer); timer = null; isEnabled = false; GM_setValue(STATE_KEY.isEnabled, false); } function restartTimer() { stopTimer(); startTimer(); } // 初始化 const uiElements = createUI(); // 自动启动 if (isEnabled) { startTimer(); } // 页面卸载清理 window.addEventListener('beforeunload', () => { GM_setValue(INSTANCE_KEY, false); }); })();