您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
页面滑动时暂停动画和视频,松手后恢复,仅保留音频播放
// ==UserScript== // @name 滑动时暂停动画与视频(保留音频) // @namespace http://tampermonkey.net/ // @version 0.2 // @description 页面滑动时暂停动画和视频,松手后恢复,仅保留音频播放 // @author Your Name // @match *://*/* // @grant none // ==/UserScript== (function () { 'use strict'; // 存储动画和视频状态 const animationStates = new Map(); const videoStates = new Map(); let rafIds = []; let intervalIds = []; let timeoutIds = []; // 节流函数,优化滚动事件 function throttle(fn, wait) { let lastCall = 0; return function (...args) { const now = performance.now(); if (now - lastCall >= wait) { lastCall = now; fn.apply(this, args); } }; } // 暂停CSS动画和过渡 function pauseCSSAnimations() { const elements = document.querySelectorAll('[style*="animation"], [style*="transition"]'); elements.forEach((element) => { const computedStyle = getComputedStyle(element); if (computedStyle.animationName !== 'none') { animationStates.set(element, element.style.animationPlayState || 'running'); element.style.animationPlayState = 'paused'; } if (computedStyle.transitionProperty !== 'none') { // 暂停过渡通过添加类或临时移除transition animationStates.set(element, element.style.transition || ''); element.style.transition = 'none'; } }); } // 恢复CSS动画和过渡 function resumeCSSAnimations() { animationStates.forEach((state, element) => { if (state.includes('animation')) { element.style.animationPlayState = state; } else if (state.includes('transition')) { element.style.transition = state; } }); animationStates.clear(); } // 暂停JavaScript动画 function pauseJavaScriptAnimations() { // 代理requestAnimationFrame const originalRAF = window.requestAnimationFrame; window.requestAnimationFrame = function (callback) { rafIds.push(originalRAF(callback)); return rafIds[rafIds.length - 1]; }; // 代理setInterval和setTimeout const originalSetInterval = window.setInterval; window.setInterval = function (callback, delay) { intervalIds.push(originalSetInterval(callback, delay)); return intervalIds[intervalIds.length - 1]; }; const originalSetTimeout = window.setTimeout; window.setTimeout = function (callback, delay) { timeoutIds.push(originalSetTimeout(callback, delay)); return timeoutIds[timeoutIds.length - 1]; }; // 取消现有动画 rafIds.forEach((id) => window.cancelAnimationFrame(id)); intervalIds.forEach((id) => window.clearInterval(id)); timeoutIds.forEach((id) => window.clearTimeout(id)); rafIds = []; intervalIds = []; timeoutIds = []; } // 恢复JavaScript动画(简化处理,需根据具体页面调整) function resumeJavaScriptAnimations() { // 恢复需要页面重新调用动画逻辑,实际情况需定制 window.requestAnimationFrame = window.requestAnimationFrame.bind(window); window.setInterval = window.setInterval.bind(window); window.setTimeout = window.setTimeout.bind(window); } // 暂停视频(保留音频) function pauseVideos() { const videos = document.getElementsByTagName('video'); for (let video of videos) { if (!video.paused) { videoStates.set(video, true); video.pause(); video.muted = false; // 确保音频继续 } } } // 恢复视频 function resumeVideos() { videoStates.forEach((wasPlaying, video) => { if (wasPlaying && video.paused) { video.play().catch((err) => console.warn('Video resume failed:', err)); } }); videoStates.clear(); } // 暂停Canvas动画 function pauseCanvasAnimations() { const canvases = document.getElementsByTagName('canvas'); for (let canvas of canvases) { const context = canvas.getContext('2d') || canvas.getContext('webgl') || canvas.getContext('webgl2'); if (context && canvas.dataset.rafId) { window.cancelAnimationFrame(parseInt(canvas.dataset.rafId)); } } } // 暂停SVG动画 function pauseSVGAAnimations() { const svgElements = document.querySelectorAll('svg animate, svg animateTransform'); svgElements.forEach((element) => { animationStates.set(element, element.getAttribute('begin') || '0s'); element.setAttribute('begin', 'indefinite'); }); } // 恢复SVG动画 function resumeSVGAAnimations() { animationStates.forEach((state, element) => { if (element.tagName.toLowerCase().startsWith('animate')) { element.setAttribute('begin', state); } }); } // 暂停Web Animations API function pauseWebAnimations() { document.getAnimations().forEach((animation) => { animationStates.set(animation, animation.playState); animation.pause(); }); } // 恢复Web Animations API function resumeWebAnimations() { animationStates.forEach((state, animation) => { if (state === 'running') { animation.play(); } }); } // 暂停GIF(简单隐藏,需第三方库支持更精确控制) function pauseGIFs() { const images = document.querySelectorAll('img[src$=".gif"]'); images.forEach((img) => { animationStates.set(img, img.style.display || 'block'); img.style.display = 'none'; }); } // 恢复GIF function resumeGIFs() { animationStates.forEach((state, img) => { if (img.tagName.toLowerCase() === 'img') { img.style.display = state; } }); } // 监控动态DOM变化 function observeDOM() { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.addedNodes.length) { // 检测新添加的视频、canvas、svg等 pauseVideos(); pauseCanvasAnimations(); pauseSVGAAnimations(); } }); }); observer.observe(document.body, { childList: true, subtree: true }); } // 滑动事件处理 let isScrolling = false; const scrollHandler = throttle(() => { if (!isScrolling) { isScrolling = true; pauseCSSAnimations(); pauseJavaScriptAnimations(); pauseVideos(); pauseCanvasAnimations(); pauseSVGAAnimations(); pauseWebAnimations(); pauseGIFs(); } }, 100); // 滑动结束检测 function handleScrollEnd() { if (isScrolling) { isScrolling = false; resumeCSSAnimations(); resumeJavaScriptAnimations(); resumeVideos(); resumeCanvasAnimations(); resumeSVGAAnimations(); resumeWebAnimations(); resumeGIFs(); } } // 监听滚动和触摸事件 document.addEventListener('scroll', scrollHandler); document.addEventListener('scrollend', handleScrollEnd); document.addEventListener('touchend', handleScrollEnd); document.addEventListener('mouseup', handleScrollEnd); // 初始化DOM监控 observeDOM(); // 清理事件监听器 window.addEventListener('unload', () => { document.removeEventListener('scroll', scrollHandler); document.removeEventListener('scrollend', handleScrollEnd); document.removeEventListener('touchend', handleScrollEnd); document.removeEventListener('mouseup', handleScrollEnd); }); })();