您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
[EN] Shows a refresh button after pulling down at the top of the page. No auto-refresh, optimized performance.
// ==UserScript== // @name Mobile Refresh Button / Botão de Atualização Mobile // @name:pt-BR Botão de Atualização Mobile // @namespace https://github.com/BrunoFortunatto // @version 1.5 // @description [EN] Shows a refresh button after pulling down at the top of the page. No auto-refresh, optimized performance. // @description:pt-BR Exibe um botão de atualização após gesto de puxar no topo da página. Sem recarregamento automático e otimizado. // @author Bruno Fortunato // @match *://*/* // @grant none // @license MIT // ==/UserScript== (function () { 'use strict'; // Evitar execução dentro de iframes if (window.self !== window.top) return; // Evitar múltiplas instâncias if (document.getElementById('refreshBtn')) return; document.body.style.overscrollBehaviorY = 'contain'; let touchStartY = 0; let pulling = false; let cooldown = false; let showTimeout = null; const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches; // Detectar idioma do navegador const userLang = navigator.language.startsWith('pt') ? 'pt' : 'en'; // Texto do botão em diferentes idiomas const buttonText = userLang === 'pt' ? 'Atualizar página' : 'Refresh page'; // Criar estilos no <head> para evitar bloqueio de CSP const style = document.createElement('style'); style.textContent = ` #refreshBtn { position: fixed; top: -50px; left: 50%; transform: translateX(-50%) scale(0.9); padding: 12px; font-size: 16px; border-radius: 25px; border: none; z-index: 9999; background-color: ${isDark ? '#444' : '#2196f3'}; color: #fff; box-shadow: 0 2px 6px rgba(0,0,0,0.3); display: flex; align-items: center; gap: 8px; opacity: 0; transition: top 0.3s ease-out, opacity 0.3s, transform 0.3s; } .refresh-icon { width: 22px; height: 22px; } @media (max-width: 480px) { #refreshBtn { font-size: 14px; padding: 10px; } .refresh-icon { width: 18px; height: 18px; } } @media (min-width: 1024px) { #refreshBtn { font-size: 18px; padding: 14px; } .refresh-icon { width: 24px; height: 24px; } } `; document.head.appendChild(style); // Criar botão de atualização const refreshBtn = document.createElement('button'); refreshBtn.id = 'refreshBtn'; // Ícone SVG embutido refreshBtn.innerHTML = ` <svg class="refresh-icon" viewBox="0 0 24 24" fill="white" xmlns="http://www.w3.org/2000/svg"> <path d="M12 2V4C16.42 4 20 7.58 20 12C20 16.42 16.42 20 12 20C7.58 20 4 16.42 4 12H2C2 17.52 6.48 22 12 22C17.52 22 22 17.52 22 12C22 6.48 17.52 2 12 2ZM7 11V13H13V11H7Z"/> </svg> ${buttonText} `; refreshBtn.addEventListener('click', () => { location.reload(); }); document.body.appendChild(refreshBtn); function showRefreshButton() { if (cooldown) return; cooldown = true; setTimeout(() => (cooldown = false), 1000); refreshBtn.style.display = 'flex'; requestAnimationFrame(() => { refreshBtn.style.top = '10px'; refreshBtn.style.opacity = '1'; refreshBtn.style.transform = 'translateX(-50%) scale(1)'; }); if (showTimeout) clearTimeout(showTimeout); showTimeout = setTimeout(hideRefreshButton, 4000); } function hideRefreshButton() { refreshBtn.style.opacity = '0'; refreshBtn.style.transform = 'translateX(-50%) scale(0.9)'; refreshBtn.style.top = '-50px'; setTimeout(() => { refreshBtn.style.display = 'none'; }, 300); } window.addEventListener('touchstart', (e) => { if (window.scrollY <= 0) { touchStartY = e.touches[0].clientY; pulling = true; } }, { passive: true }); window.addEventListener('touchmove', (e) => { if (!pulling) return; const deltaY = e.touches[0].clientY - touchStartY; if (deltaY > 25 && window.scrollY === 0) { showRefreshButton(); pulling = false; } }, { passive: true }); window.addEventListener('scroll', () => { if (window.scrollY > 50) { pulling = false; hideRefreshButton(); } }, { passive: true }); })();