为何DOMContentLoaded在Vivaldi论坛站内跳转时不触发?
为什么DOMContentLoaded不会在Vivaldi论坛内跳转时触发?
嗨,这个问题其实挺常见的——现在不少现代论坛(包括Vivaldi这个)都用上了异步页面加载技术(比如PJAX或者类SPA模式),而不是每次页面跳转都重新加载整个HTML文档。
你得先搞懂DOMContentLoaded的触发逻辑:它只会在整个初始HTML文档被完全加载并解析完成时触发,哪怕样式表、图片还没加载完也没关系,但前提是整个文档是从头加载的。而当你在论坛内跳转时,网站根本没有重新加载整个页面,只是用JS异步替换了页面里的核心内容(比如帖子内容、列表区域),同时通过HTML5的History API修改了地址栏的URL。这种情况下,整个文档的DOM树并没有被重新构建,DOMContentLoaded自然不会再次触发。
那怎么解决这个问题?给你几个实用的方案:
方案1:监听PJAX专属事件
很多用PJAX的网站会抛出特定的自定义事件,比如pjax:complete或者pjax:success,直接监听这些事件就能捕获页面切换:
//==UserScript== //@include https://forum.vivaldi.net/* //==/UserScript== (function () { // 统一处理页面加载逻辑 function handlePageLoad() { alert('A new page is loaded'); } // 处理初始页面加载 window.addEventListener('DOMContentLoaded', handlePageLoad); // 监听PJAX跳转完成事件 document.addEventListener('pjax:complete', handlePageLoad); })();
方案2:监听History状态变化
如果网站没暴露PJAX事件,你可以通过重写pushState/replaceState方法,再结合popstate事件,捕获所有URL变化:
//==UserScript== //@include https://forum.vivaldi.net/* //==/UserScript== (function () { function handlePageLoad() { alert('A new page is loaded'); } // 初始加载触发 window.addEventListener('DOMContentLoaded', handlePageLoad); // 重写pushState,捕获主动跳转 const originalPushState = history.pushState; history.pushState = function(...args) { originalPushState.apply(this, args); handlePageLoad(); }; // 重写replaceState,捕获状态替换 const originalReplaceState = history.replaceState; history.replaceState = function(...args) { originalReplaceState.apply(this, args); handlePageLoad(); }; // 监听浏览器前进后退操作 window.addEventListener('popstate', handlePageLoad); })();
方案3:用MutationObserver监测内容变化
如果上面两种方法都不生效,你可以用MutationObserver盯着页面的核心内容区域,一旦内容发生显著变化就触发逻辑:
//==UserScript== //@include https://forum.vivaldi.net/* //==/UserScript== (function () { function handlePageLoad() { alert('A new page is loaded'); } window.addEventListener('DOMContentLoaded', function() { handlePageLoad(); // 找到论坛每次跳转都会替换的核心容器(需自己用开发者工具确认选择器) const targetNode = document.querySelector('.topic-content'); // 示例选择器,替换为实际容器 if (targetNode) { const observer = new MutationObserver(function() { // 核心内容变化时触发 handlePageLoad(); }); // 监听子节点变化和子树变化 observer.observe(targetNode, { childList: true, subtree: true }); } }); })();
注意:方案3里的选择器需要你自己用浏览器开发者工具查看Vivaldi论坛的实际DOM结构,找到每次跳转都会更新的核心容器,替换掉示例里的.topic-content。
内容的提问来源于stack exchange,提问作者user13112502
相关产品推荐
相关产品推荐

