如何通过浏览器控制台禁用无限滚动页删除顶部旧HTML的JS逻辑
为什么你写的拦截代码不生效
你之前写的Element.remove = () => { console.log("Nope!"); }失效是必然的,核心原因两个:
Element.remove()是DOM实例方法,挂载在Element.prototype原型对象上,你直接给Element构造函数本身赋值remove属性,根本不会影响页面上真实DOM节点的方法调用。- 无限滚动场景删除顶部内容几乎不会走
Element.remove()这个API,更常见的实现是调用父容器的Node.removeChild()删指定子节点、调用ParentNode.replaceChildren()替换容器内容,甚至直接给父容器的innerHTML赋值覆盖原有内容,这些操作完全不会触发你重写的remove方法。
可落地的拦截方案
不要全局拦截所有DOM删除操作,否则会把页面正常交互(比如关闭弹窗、切换按钮状态)全部搞坏,你只需要针对承载信息流的容器做定向拦截即可。
第一步:先找到信息流的容器选择器
右键点击页面上的信息流内容(比如某条推文),点「检查」定位到元素,往上找包裹所有信息流条目的最近父节点,复制它的唯一CSS选择器(比如Twitter的主时间线容器可以用对应推文条目的父级选择器,其他网站同理,只要能唯一定位到装所有信息流内容的盒子就行)。
第二步:尽早在控制台执行拦截代码
在滚动触发内容删除之前,把下面的代码粘到控制台运行,把代码里的占位选择器换成你刚才找到的实际值:
// 先缓存所有原生DOM操作方法的原始引用 const rawRemove = Element.prototype.remove; const rawRemoveChild = Node.prototype.removeChild; const rawReplaceChildren = ParentNode.prototype.replaceChildren; const rawInnerHTMLSetter = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').set; const rawAppend = ParentNode.prototype.append; // 拦截节点自身remove调用 Element.prototype.remove = function() { if (this.closest('替换成你的信息流容器选择器')) { console.log('拦截remove操作,保留旧内容', this); return; } return rawRemove.apply(this, arguments); }; // 拦截父容器调用removeChild删子节点 Node.prototype.removeChild = function(child) { if (child.closest('替换成你的信息流容器选择器')) { console.log('拦截removeChild操作,保留旧内容', child); return child; } return rawRemoveChild.apply(this, arguments); }; // 拦截replaceChildren替换容器内容 ParentNode.prototype.replaceChildren = function(...nodes) { if (this.matches('替换成你的信息流容器选择器')) { console.log('拦截replaceChildren操作,改为追加新内容'); return rawAppend.apply(this, nodes); } return rawReplaceChildren.apply(this, arguments); }; // 拦截覆写innerHTML清空内容的操作 Object.defineProperty(Element.prototype, 'innerHTML', { set: function(val) { if (this.matches('替换成你的信息流容器选择器')) { console.log('拦截innerHTML覆写,跳过清空操作'); return; } return rawInnerHTMLSetter.call(this, val); }, get: Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML').get, configurable: true });
兜底方案:用MutationObserver恢复被删内容
如果网站做了特殊处理,提前缓存了原生方法导致上面的原型拦截失效,可以用DOM变动监听做兜底,只要监听到信息流容器里有内容被删掉,就立刻把节点插回原位置:
const timelineContainer = document.querySelector('替换成你的信息流容器选择器'); const observer = new MutationObserver(mutations => { mutations.forEach(mut => { mut.removedNodes.forEach(node => { if (node.nodeType !== Node.ELEMENT_NODE) return; // 这里可以加判断,只恢复你需要保留的信息流条目 console.log('恢复被删除的信息流内容', node); mut.target.insertBefore(node, mut.nextSibling); }); }); }); observer.observe(timelineContainer, { childList: true, subtree: false });
提醒:禁用顶部内容删除后,随着你滚动加载的内容变多,页面内存占用会持续上涨,滚动流畅度会越来越差,这也是无限滚动类产品默认只保留固定数量DOM节点的核心原因。
内容的提问来源于stack exchange,提问作者Mew
相关产品推荐
相关产品推荐

