您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Intelligently reverses ill-conceived element fixing on sites like Medium.com
当前为
// ==UserScript== // @name Unfix Fixed Elements // @namespace http://tampermonkey.net/ // @version 1.2 // @description Intelligently reverses ill-conceived element fixing on sites like Medium.com // @author alienfucker // @match *://*/* // @grant none // @noframes // @run-at document_start // ==/UserScript== (function () { 'use strict'; const className = "anti-fixing"; // Odds of colliding with another class must be low class FixedWatcher { constructor() { this.watcher = new MutationObserver(this.onMutation.bind(this)); this.elementTypes = ["div", "header", "footer", "nav"]; this.awaitingTick = false; this.top = []; this.bottom = []; this.processedMiddle = false; } start() { this.trackAll(); this.watcher.observe(document, { childList: true, attributes: true, subtree: true, attributeFilter: ["class", "style"], attributeOldValue: true }); window.addEventListener("scroll", this.onScroll.bind(this)); } onScroll(){ if(this.awaitingTick) return; this.awaitingTick = true; window.requestAnimationFrame(() => { const max = document.body.scrollHeight - window.innerHeight; const y = window.scrollY; for(const item of this.top){ item.className = item.el.className; if(y === 0){ item.el.classList.remove(className); }else if(!item.el.classList.contains(className)){ item.el.classList.add(className); } } for(const item of this.bottom){ item.className = item.el.className; if(y === max){ item.el.classList.remove(className); }else if(!item.el.classList.contains(className)){ item.el.classList.add(className); } } this.awaitingTick = false; }) } onMutation(mutations) { for (let mutation of mutations) { if (mutation.type === "childList") { for(let node of mutation.removedNodes) this.untrack(node) for (let node of mutation.addedNodes) { if (node.nodeType !== Node.ELEMENT_NODE) continue; if (this.elementTypes.findIndex(selector => node.matches(selector)) !== -1) this.track(node); node.querySelectorAll(this.elementTypes.join(",")).forEach(el => this.track(el)); } } else if (mutation.type === "attributes") { if (this.friendlyMutation(mutation)) continue; if (this.elementTypes.findIndex(selector => mutation.target.matches(selector)) !== -1) { this.track(mutation.target); } } } } friendlyMutation(mutation){ // Mutation came from us if(mutation.attributeName === "class"){ if(this.top.findIndex(({el, className}) => el === mutation.target && className === mutation.oldValue) !== -1) return true; if(this.bottom.findIndex(({el, className}) => el === mutation.target && className === mutation.oldValue) !== -1) return true; } return false; } untrack(_el){ let i = this.top.findIndex(({el}) => el.isSameNode(_el) || _el.contains(el)); if(i !== -1) return !!this.top.splice(i, 1); i = this.bottom.findIndex(({el}) => el.isSameNode(_el) || _el.contains(el)); if(i !== -1) return !!this.bottom.splice(i, 1); return false; } trackAll(){ const els = document.querySelectorAll(this.elementTypes.join(",")); for(const el of els) this.track(el); } getClassAttribs(el){ // Last-ditch effort to help figure out if the developer intended the fixed element to be fullscreen // i.e. explicitly defined both the top and bottom rules. If they did, then we leave the element alone. // Unfortunately, we can't get this info from .style or computedStyle, since .style only // applies when the rules are added directly to the element, and computedStyle automatically generates a value // for top/bottom if the opposite is set. Leaving us no way to know if the developer actually set the other value. const rules = []; for(const styleSheet of document.styleSheets){ try{ for(const rule of styleSheet.rules){ if(el.matches(rule.selectorText)){ rules.push({height: rule.style.height, top: rule.style.top, bottom: rule.style.bottom}); } } }catch(e) { continue; } } return rules.reduce((current, next) => ({ height: next.height || current.height, top: next.top || current.top, bottom: next.bottom || current.bottom }),{ height: "", top: "", bottom: "" }); } isAutoBottom(el, style){ if(style.bottom === "auto") return true; if(style.bottom === "0px") return false; if(el.style.bottom.length) return false; const {height, bottom} = this.getClassAttribs(el); if(height === "100%" || bottom.length) return false; return true; } isAutoTop(el, style){ if(style.top === "auto") return true; if(style.top === "0px") return false; if(el.style.top.length) return false; const {height, top} = this.getClassAttribs(el); if(height === "100%" || top.length) return false; return true; } topTracked(el){ return this.top.findIndex(({el: _el}) => _el === el) !== -1 } bottomTracked(el){ return this.bottom.findIndex(({el: _el}) => _el === el) !== -1 } track(el){ const style = window.getComputedStyle(el); if (style.position === "fixed" || style.position === "sticky") { console.log(el, style.top === "0px", style.top.indexOf("-") === 0, !this.topTracked(el), this.isAutoBottom(el, style)); if((style.top === "0px" || style.top.indexOf("-") === 0) && !this.topTracked(el) && this.isAutoBottom(el, style)){ this.top.push({el, className: el.className}); this.onScroll(); }else if((style.bottom === "0px" || style.bottom.indexOf("-") === 0) && !this.bottomTracked(el) && this.isAutoTop(el, style)){ this.bottom.push({el, className: el.className}); this.onScroll(); } } } stop() { this.watcher.disconnect(); window.removeEventListener("scroll", this.onScroll.bind(this)); } restore() { let els = document.querySelectorAll("." + className); for (let el of els) { el.classList.remove(className); } } } document.documentElement.appendChild((() => { let el = document.createElement("style"); el.setAttribute("type", "text/css"); el.appendChild(document.createTextNode(`.${className}{ display: none !important }`)); //el.appendChild(document.createTextNode(`.${className}{ position: static !important }`)); return el; })()) window.addEventListener("keypress", e => { if(e.key === "F"){ if(window.fixer){ console.log("Removing fixer"); fixer.stop(); fixer.restore(); window.fixer = null; }else{ console.log("Adding fixer"); fixer = new FixedWatcher(); fixer.start(); window.fixer = fixer; } } }); let fixer = new FixedWatcher(); fixer.start(); // Make globally accessible, for debugging purposes window.fixer = fixer; })()
QingJ © 2025
镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址