您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Adds a customizable scroll-to-top button near the page bottom.
当前为
// ==UserScript== // @name Scroll to Top Button // @namespace sttb-ujs-dxrk1e // @description Adds a customizable scroll-to-top button near the page bottom. // @icon https://i.imgur.com/FxF8TLS.png // @match *://*/* // @grant none // @version 2.4.0 // @author DXRK1E // @license MIT // ==/UserScript== (function() { 'use strict'; const APP_CONFIG = { button: { size: '45px', fontSize: '18px', backgroundColor: '#3a3a3a', hoverColor: '#555', textColor: '#f5f5f5', borderRadius: '55%', position: { bottom: '25px', right: '25px' }, shadow: '0 3px 10px rgba(0,0,0,0.45)', transitionSpeed: 350, zIndex: 2147483647, svg: { width: '20px', height: '20px', viewBox: '0 0 16 16' } }, behavior: { showThreshold: 350, bottomThreshold: 200, // Pixels from the bottom debounceDelay: 175, enableSmoothScroll: true, }, scroll: { duration: 900, // Duration of scroll animation in ms easing: 'easeInOutCubic', // Easing function for smooth acceleration/deceleration fps: 60, // Frames per second for smooth animation breakpoints: { // Adjust scroll speed based on distance short: 550, // px medium: 1600, // px long: 3200 // px } } }; const EASING_FUNCTIONS = { easeInOutCubic: t => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2, easeOutQuad: t => 1 - (1 - t) * (1 - t), easeInOutExpo: t => t === 0 ? 0 : t === 1 ? 1 : t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2, }; function createButtonElement() { const button = document.createElement('button'); button.id = 'enhanced-scroll-button'; button.innerHTML = ` <svg width="${APP_CONFIG.button.svg.width}" height="${APP_CONFIG.button.svg.height}" viewBox="${APP_CONFIG.button.svg.viewBox}" fill="none" xmlns="http://www.w3.org/2000/svg"> <path d="M8 3L14 9L12.6 10.4L8 5.8L3.4 10.4L2 9L8 3Z" fill="currentColor"/> </svg> `; Object.assign(button.style, { position: 'fixed', bottom: APP_CONFIG.button.position.bottom, right: APP_CONFIG.button.position.right, width: APP_CONFIG.button.size, height: APP_CONFIG.button.size, fontSize: APP_CONFIG.button.fontSize, backgroundColor: APP_CONFIG.button.backgroundColor, color: APP_CONFIG.button.textColor, border: 'none', borderRadius: APP_CONFIG.button.borderRadius, cursor: 'pointer', boxShadow: APP_CONFIG.button.shadow, opacity: '0', visibility: 'hidden', zIndex: APP_CONFIG.button.zIndex, transition: `all ${APP_CONFIG.button.transitionSpeed}ms ease-in-out`, display: 'flex', alignItems: 'center', justifyContent: 'center', padding: '0', transform: 'scale(1)', outline: 'none' }); button.addEventListener('mouseenter', () => setButtonHoverStyle(button)); button.addEventListener('mouseleave', () => resetButtonStyles(button)); button.addEventListener('mousedown', () => setButtonPressStyle(button)); button.addEventListener('mouseup', () => setButtonHoverStyle(button)); return button; } function setButtonHoverStyle(button) { button.style.backgroundColor = APP_CONFIG.button.hoverColor; button.style.transform = 'scale(1.1)'; } function resetButtonStyles(button) { button.style.backgroundColor = APP_CONFIG.button.backgroundColor; button.style.transform = 'scale(1)'; } function setButtonPressStyle(button) { button.style.transform = 'scale(0.95)'; } function smoothScrollToTop() { if(!APP_CONFIG.behavior.enableSmoothScroll) { window.scrollTo({ top: 0, behavior: 'auto' }); return; } const startPosition = getScrollPosition(); const startTime = performance.now(); let scrollDuration = APP_CONFIG.scroll.duration; if (startPosition < APP_CONFIG.scroll.breakpoints.short) { scrollDuration *= 0.7; } else if (startPosition > APP_CONFIG.scroll.breakpoints.long) { scrollDuration *= 1.3; } function animationStep(currentTime) { const timeElapsed = currentTime - startTime; const progress = Math.min(timeElapsed / scrollDuration, 1); const easedProgress = EASING_FUNCTIONS[APP_CONFIG.scroll.easing](progress); const newPosition = startPosition - (startPosition * easedProgress); window.scrollTo(0, newPosition); if (timeElapsed < scrollDuration) { requestAnimationFrame(animationStep); } } requestAnimationFrame(animationStep); } function getScrollPosition() { return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0; } function debounce(func, wait, immediate = false) { let timeoutId; let lastArgs; return function(...args) { lastArgs = args; const later = () => { timeoutId = null; if (!immediate) { func.apply(this, lastArgs); } }; const callNow = immediate && !timeoutId; clearTimeout(timeoutId); timeoutId = setTimeout(later, wait); if (callNow) { func.apply(this, lastArgs); } }; } function shouldShowButton() { const scrollHeight = Math.max( document.documentElement.scrollHeight, document.body.scrollHeight ); const viewportHeight = window.innerHeight; const scrollTop = getScrollPosition(); const bottomScroll = scrollHeight - viewportHeight - APP_CONFIG.behavior.bottomThreshold; return ( scrollTop > APP_CONFIG.behavior.showThreshold && scrollTop >= bottomScroll ); } function handleScrollEvent() { const button = document.getElementById('enhanced-scroll-button'); if (!button) return; if (shouldShowButton()) { button.style.visibility = 'visible'; button.style.opacity = '1'; } else { button.style.opacity = '0'; setTimeout(() => { if (button.style.opacity === '0') { button.style.visibility = 'hidden'; } }, APP_CONFIG.button.transitionSpeed); } } function initialize() { const existingButton = document.getElementById('enhanced-scroll-button'); if (existingButton) return; const scrollButton = createButtonElement(); document.body.appendChild(scrollButton); const debouncedScrollHandler = debounce(handleScrollEvent, APP_CONFIG.behavior.debounceDelay); window.addEventListener('scroll', debouncedScrollHandler, { passive: true }); window.addEventListener('resize', debouncedScrollHandler, { passive: true }); const mutationObserver = new MutationObserver(debouncedScrollHandler); mutationObserver.observe(document.documentElement, { childList: true, subtree: true }); scrollButton.addEventListener('click', (event) => { event.preventDefault(); smoothScrollToTop(); }); handleScrollEvent(); // Initial button state } // Initialization on DOM ready if (document.readyState === 'loading') { document.addEventListener('DOMContentLoaded', initialize); } else { initialize(); } })();
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址