// ==UserScript== // @name DeepSeek一键回顶 // @namespace https://scriptcat.org/zh-CN/users/214553 // @version 1.2.0 // @description 在DeepSeek网页上添加「回到顶部」按钮,一键回到对话的最开始。 // @author English3(Σπg|!εh๑๑๑) // @license MIT // @icon https://deepseek.com/favicon.ico // @match https://chat.deepseek.com/* // @run-at document-idle // @grant none // ==/UserScript== (() => { 'use strict'; const ID = 'ds-back-top-v5'; const goTop = () => { try { let bestEl = null; let maxScrollHeight = 0; document.querySelectorAll('div, main, section').forEach(el => { const style = window.getComputedStyle(el); if ((style.overflowY === 'auto' || style.overflowY === 'scroll') && el.scrollHeight > maxScrollHeight && el.clientHeight > 100) { maxScrollHeight = el.scrollHeight; bestEl = el; } }); if (bestEl) { bestEl.setAttribute('tabindex', '-1'); bestEl.focus(); const homeEvent = new KeyboardEvent('keydown', { key: 'Home', code: 'Home', keyCode: 36, which: 36, bubbles: true, cancelable: true }); bestEl.dispatchEvent(homeEvent); setTimeout(() => { bestEl.scrollTo({ top: 0, behavior: 'smooth' }); }, 50); } else { window.scrollTo({ top: 0, behavior: 'smooth' }); document.documentElement.scrollTop = 0; } } catch (e) { console.warn('回顶异常:', e); } }; // 创建统一按钮 const btn = document.createElement('button'); btn.id = ID; btn.type = 'button'; btn.title = '回到顶部'; btn.setAttribute('aria-label', '回到顶部'); // 这里用 SVG 图标,适用于两种情况 btn.innerHTML = ` `; // 鼠标悬停效果(电脑端) btn.onmouseenter = () => { if (btn.dataset.mode === 'pc') btn.style.opacity = '1'; }; btn.onmouseleave = () => { if (btn.dataset.mode === 'pc') btn.style.opacity = '0.8'; }; btn.addEventListener('click', (e) => { e.preventDefault(); e.stopPropagation(); goTop(); }); // 判断是否为手机端(宽度小于768px视为手机) const isMobile = () => window.innerWidth <= 768; // 手机端:寻找顶栏的分享按钮,插在它左边 const insertToMobileHeader = () => { const allBtns = Array.from(document.querySelectorAll('button, [role="button"]')); const W = window.innerWidth; // 找出位于顶部区域、且宽度在右侧的按钮 const topRightBtns = allBtns.filter(b => { const r = b.getBoundingClientRect(); return r.top < 60 && r.left > W * 0.5 && r.width > 0 && b.id !== ID; }).sort((a, b) => a.getBoundingClientRect().left - b.getBoundingClientRect().left); if (topRightBtns.length > 0) { // 找到最右侧的分享按钮 const shareBtn = topRightBtns[topRightBtns.length - 1]; const parent = shareBtn.parentElement; if (parent && btn.parentElement !== parent) { parent.insertBefore(btn, shareBtn); // 应用手机端顶部栏样式 btn.dataset.mode = 'mobile'; Object.assign(btn.style, { position: 'relative', right: 'auto', bottom: 'auto', width: '32px', height: '32px', borderRadius: '8px', background: 'transparent', color: 'inherit', zIndex: 'auto', boxShadow: 'none', opacity: '1', margin: '0 4px', padding: '0', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: '0' }); return true; } } return false; }; // 电脑端:右侧悬浮固定 const setPcFloatingStyle = () => { btn.dataset.mode = 'pc'; Object.assign(btn.style, { position: 'fixed', right: '24px', bottom: '120px', width: '46px', height: '46px', borderRadius: '50%', background: 'rgba(0, 0, 0, 0.6)', color: '#ffffff', border: '2px solid rgba(255,255,255,0.2)', zIndex: '9999999', boxShadow: '0 4px 12px rgba(0,0,0,0.3)', opacity: '0.8', margin: '0', padding: '0', display: 'flex', alignItems: 'center', justifyContent: 'center', transition: 'all 0.2s ease', cursor: 'pointer' }); }; const ensureMount = () => { if (!document.body) return; // 手机端逻辑 if (isMobile()) { // 如果已经正确插入顶栏,什么都不做 if (btn.dataset.mode === 'mobile' && btn.parentElement && btn.parentElement.tagName !== 'BODY') return; // 尝试插入顶栏,如果失败(比如页面还没加载完),则退化为悬浮 if (!insertToMobileHeader()) { if (!btn.isConnected) document.body.appendChild(btn); setPcFloatingStyle(); // 手机端页面未加载完时,先放个悬浮兜底 } } // 电脑端逻辑:坚决使用悬浮 else { if (!btn.isConnected) document.body.appendChild(btn); // 如果当前处于手机顶栏模式,重置为电脑悬浮模式 if (btn.dataset.mode !== 'pc') { setPcFloatingStyle(); } } }; // 启动与持续监听 ensureMount(); // 使用定时器防止按钮被React重绘删除,并处理页面缩放 setInterval(ensureMount, 1000); // 页面加载初期的延迟挂载 setTimeout(ensureMount, 500); setTimeout(ensureMount, 2000); })();