// ==UserScript== // @name 页面导航 // @namespace http://tampermonkey.net/ // @version 1.0.0 // @description 在右下角增添可以置顶或置底的按钮,长按可拖动 // @author G31415 // @match *://*/* // @grant none // @license MIT // @downloadURL https://update.greasyfork.icu/scripts/566182/%E9%A1%B5%E9%9D%A2%E5%AF%BC%E8%88%AA.user.js // @updateURL https://update.greasyfork.icu/scripts/566182/%E9%A1%B5%E9%9D%A2%E5%AF%BC%E8%88%AA.meta.js // ==/UserScript== (function() { const id = 'g' + Math.random().toString(36).slice(2,7); const btn = Object.assign(document.createElement('button'), { id, textContent: '▼', title: '点击跳转' }); // 状态变量 let isDragging = false, dragActive = false, pressTimer = null; let startX, startY, startRight, startBottom; let lastY = window.scrollY; const style = document.createElement('style'); style.textContent = ` #${id} { all: initial; position: fixed; bottom: 0; right: 0; width: 32px; height: 32px; font: 16px/32px sans-serif; text-align: center; color: #000; background: transparent; border: none; cursor: pointer; z-index: 9999; user-select: none; -webkit-tap-highlight-color: transparent; outline: none; /* 取消蓝色方框 */ display: none; touch-action: none; /* 核心:防止移动端手势干扰拖拽 */ } #${id}.visible { display: block; } #${id}:hover { transform: scale(1); } #${id}:active { transform: scale(0.82); } #${id}.dragging { opacity: 0.6; cursor: grabbing; transform: scale(1); transition: none; } @media (max-width: 768px) { #${id} { width: 44px; height: 44px; font-size: 26px; line-height: 44px; } } `; document.head.appendChild(style); document.body.appendChild(btn); // 拖拽逻辑更新为 Pointer 事件(支持鼠标和触摸) const handlePointerMove = (e) => { if (!dragActive) return; const deltaX = e.clientX - startX; const deltaY = e.clientY - startY; // 计算新位置并限制在视口内 let newRight = Math.max(0, Math.min(window.innerWidth - btn.offsetWidth, startRight - deltaX)); let newBottom = Math.max(0, Math.min(window.innerHeight - btn.offsetHeight, startBottom - deltaY)); btn.style.right = newRight + 'px'; btn.style.bottom = newBottom + 'px'; }; btn.onpointerdown = (e) => { if (e.button !== 0 && e.pointerType === 'mouse') return; pressTimer = setTimeout(() => { dragActive = isDragging = true; btn.classList.add('dragging'); // 锁定指针,拖拽更稳 btn.setPointerCapture(e.pointerId); startX = e.clientX; startY = e.clientY; const s = getComputedStyle(btn); startRight = parseFloat(s.right) || 0; startBottom = parseFloat(s.bottom) || 0; }, 500); }; btn.onpointerup = (e) => { clearTimeout(pressTimer); if (dragActive) { dragActive = isDragging = false; btn.classList.remove('dragging'); btn.releasePointerCapture(e.pointerId); } else if (pressTimer && btn.classList.contains('visible')) { // 短按触发跳转 const isToTop = btn.textContent === '▲'; window.scrollTo(0, isToTop ? 0 : document.documentElement.scrollHeight); } pressTimer = null; }; // 全局移动监听 window.addEventListener('pointermove', handlePointerMove); // 滚动监听(增加性能节流) let ticking = false; window.addEventListener('scroll', () => { if (!ticking) { window.requestAnimationFrame(() => { const y = window.scrollY; if (y > 0) btn.classList.add('visible'); if (btn.classList.contains('visible') && Math.abs(y - lastY) > 5) { const isDown = y > lastY; btn.textContent = isDown ? '▼' : '▲'; btn.title = isDown ? '点击跳转到底部' : '点击跳转到顶部'; } lastY = y; ticking = false; }); ticking = true; } }, { passive: true }); // 守护按钮不被意外删除 new MutationObserver(muts => muts.forEach(m => m.removedNodes.forEach(n => n.id === id && document.body.appendChild(btn)) )).observe(document.body, { childList: true }); })();