您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
每次在ChatGPT或Gemini提问时,页面总是自动滚动到底部,我还没看完上一个答案就被强制跳到新答案了,非常影响体验
// ==UserScript== // @name AI Chat Auto-Scroll Blocker // @name:zh-CN 锁定聊天页面滚动 ChatGPT & Gemini & Claude // @namespace https://greasyfork.org/ // @version 1.0 // @description Prevents ChatGPT, Gemini, and Claude from auto-scrolling during conversations, giving you full control over your reading experience // @description:zh-CN 每次在ChatGPT或Gemini提问时,页面总是自动滚动到底部,我还没看完上一个答案就被强制跳到新答案了,非常影响体验 // @author Efficient Lazy Panda // @match https://chatgpt.com/* // @match https://chat.openai.com/* // @match https://gemini.google.com/* // @match https://bard.google.com/* // @match https://claude.ai/* // @grant none // @run-at document-start // @license MIT // ==/UserScript== (function() { 'use strict'; let scrollBlocked = true; // 默认阻止自动滚动 let originalScrollIntoView = null; let originalScrollTo = null; let originalScrollTop = null; // 阻止自动滚动 function blockAutoScroll() { // 保存原始函数 if (!originalScrollIntoView) { originalScrollIntoView = Element.prototype.scrollIntoView; originalScrollTo = window.scrollTo; originalScrollTop = Object.getOwnPropertyDescriptor(Element.prototype, 'scrollTop') || Object.getOwnPropertyDescriptor(HTMLElement.prototype, 'scrollTop'); } Element.prototype.scrollIntoView = function(options) { if (scrollBlocked) { console.log('阻止了 scrollIntoView 调用'); return false; } return originalScrollIntoView.call(this, options); }; window.scrollTo = function(x, y) { if (scrollBlocked) { // 只阻止向下滚动 if (y > window.scrollY) { console.log('阻止了向下 scrollTo 调用:', x, y); return false; } } return originalScrollTo.call(this, x, y); }; if (originalScrollTop) { Object.defineProperty(Element.prototype, 'scrollTop', { get: function() { return originalScrollTop.get ? originalScrollTop.get.call(this) : 0; }, set: function(value) { if (scrollBlocked && value > this.scrollTop) { console.log('阻止了向下滚动设置 scrollTop:', value); return; } if (originalScrollTop && originalScrollTop.set) { originalScrollTop.set.call(this, value); } } }); } } // 智能滚动阻止系统 function preventScrollEvents() { let lastScrollTime = 0; let scrollAttempts = 0; // 阻止自动滚动,但允许手动滚动 document.addEventListener('scroll', function(e) { const currentTime = Date.now(); const timeDiff = currentTime - lastScrollTime; if (scrollBlocked) { // 如果滚动间隔太短(可能是自动滚动) if (timeDiff < 50) { scrollAttempts++; if (scrollAttempts > 3) { console.log('检测到连续自动滚动,已阻止'); e.preventDefault(); e.stopPropagation(); return false; } } else { scrollAttempts = 0; } } lastScrollTime = currentTime; window.lastScrollY = window.scrollY; }, { capture: true, passive: false }); // 监听页面滚动行为变化 const originalSetTimeout = window.setTimeout; window.setTimeout = function(callback, delay, ...args) { if (scrollBlocked && delay > 0 && delay < 1000) { // 检查回调函数是否可能执行滚动 const callbackStr = callback.toString(); if (callbackStr.includes('scroll') || callbackStr.includes('scrollIntoView') || callbackStr.includes('scrollTop')) { console.log('阻止可能的自动滚动定时器'); return originalSetTimeout(() => {}, delay); } } return originalSetTimeout.call(this, callback, delay, ...args); }; } // ChatGPT 特定的防滚动修复 function applyChatGPTFix() { let lastScrollPosition = 0; const observer = new MutationObserver((mutations) => { if (scrollBlocked) { mutations.forEach((mutation) => { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { const selectors = [ '[data-testid^="conversation-turn"]', '[role="presentation"]', '.group.w-full', '.flex.w-full.items-center', 'article', '.prose', '[data-message-author-role]' ]; let foundMessage = false; selectors.forEach(selector => { if (node.matches && node.matches(selector) || node.querySelector && node.querySelector(selector)) { foundMessage = true; } }); if (foundMessage) { console.log('检测到 ChatGPT 新消息,阻止自动滚动'); setTimeout(() => { if (window.scrollY > lastScrollPosition + 50) { window.scrollTo(0, lastScrollPosition); } }, 100); } } }); } }); } lastScrollPosition = window.scrollY; }); window.addEventListener('scroll', () => { if (!scrollBlocked) { lastScrollPosition = window.scrollY; } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); setInterval(() => { if (scrollBlocked) { const currentScroll = window.scrollY; if (currentScroll > lastScrollPosition + 100) { console.log('ChatGPT: 阻止意外的大幅滚动'); window.scrollTo(0, lastScrollPosition); } } }, 200); } function applyGeminiFix() { let lastScrollPosition = 0; const observer = new MutationObserver((mutations) => { if (scrollBlocked) { mutations.forEach((mutation) => { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { const selectors = [ '[data-message-id]', '.model-response-container', '.conversation-container', '[role="log"]', '.response-container' ]; let foundMessage = false; selectors.forEach(selector => { if (node.matches && node.matches(selector) || node.querySelector && node.querySelector(selector)) { foundMessage = true; } }); if (foundMessage) { console.log('检测到 Gemini 新消息,阻止自动滚动'); setTimeout(() => { if (window.scrollY > lastScrollPosition + 50) { window.scrollTo(0, lastScrollPosition); } }, 100); } } }); } }); } lastScrollPosition = window.scrollY; }); window.addEventListener('scroll', () => { if (!scrollBlocked) { lastScrollPosition = window.scrollY; } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); setInterval(() => { if (scrollBlocked) { const currentScroll = window.scrollY; if (currentScroll > lastScrollPosition + 100) { console.log('Gemini: 阻止意外的大幅滚动'); window.scrollTo(0, lastScrollPosition); } } }, 200); } // Claude AI 的防滚动修复 function applyClaudeFix() { let lastScrollPosition = 0; const observer = new MutationObserver((mutations) => { if (scrollBlocked) { mutations.forEach((mutation) => { if (mutation.type === 'childList' && mutation.addedNodes.length > 0) { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { const selectors = [ '[data-testid="message"]', '.font-user-message', '.font-claude-message', '.message', '.conversation-message' ]; let foundMessage = false; selectors.forEach(selector => { if (node.matches && node.matches(selector) || node.querySelector && node.querySelector(selector)) { foundMessage = true; } }); if (foundMessage) { console.log('检测到 Claude AI 新消息,阻止自动滚动'); setTimeout(() => { if (window.scrollY > lastScrollPosition + 50) { window.scrollTo(0, lastScrollPosition); } }, 100); } } }); } }); } lastScrollPosition = window.scrollY; }); window.addEventListener('scroll', () => { if (!scrollBlocked) { lastScrollPosition = window.scrollY; } }); observer.observe(document.body, { childList: true, subtree: true, attributes: true }); setInterval(() => { if (scrollBlocked) { const currentScroll = window.scrollY; if (currentScroll > lastScrollPosition + 100) { console.log('Claude AI: 阻止意外的大幅滚动'); window.scrollTo(0, lastScrollPosition); } } }, 200); } // 检测网站类型并应用相应的防滚动策略 function detectSiteAndApplyFix() { const hostname = window.location.hostname; if (hostname.includes('chatgpt.com') || hostname.includes('openai.com')) { console.log('检测到 ChatGPT 网站,启用防自动滚动'); applyChatGPTFix(); } else if (hostname.includes('gemini.google.com') || hostname.includes('bard.google.com')) { console.log('检测到 Gemini 网站,启用防自动滚动'); applyGeminiFix(); } else if (hostname.includes('claude.ai')) { console.log('检测到 Claude AI 网站,启用防自动滚动'); applyClaudeFix(); } } // 初始化脚本 function init() { console.log('ChatGPT & Gemini & Claude 防自动滚动脚本 v1.0 已启动'); // 应用滚动阻止 blockAutoScroll(); // 阻止滚动事件 preventScrollEvents(); // 检测并应用网站特定修复 detectSiteAndApplyFix(); } // 立即运行初始化 init(); })();