纯 Javascript 检测 SPA DOM 就绪和页面更改

tvv*_*old 5 javascript dom-events single-page-application

当单页应用程序上的 DOM 就绪或页面视图发生更改时,我需要触发一个函数,这是我的代码,它在用户第一次访问该网站(DOM 就绪)时工作,但当用户第一次访问该站点时它不起作用切换 SPA 页面(视图已更改)。

我需要一个适用于大多数网站和 SPA 项目的通用方法,因为此代码需要在我们每个客户的网站上执行(有点像 Google Analytics 跟踪代码),并且每次最终用户加载或切换网站时都需要执行此代码页。是否有任何纯 Javascript 可以检测 SPA 何时更改页面?

function docReady(fn) {
    if (document.readyState === "complete" || document.readyState === "interactive") {
        setTimeout(fn, 1);
    } else {
        document.addEventListener("DOMContentLoaded", fn);
    }
}

docReady(function() {
    _AcodeInit();
});

function _AcodeInit()
{
...
}
Run Code Online (Sandbox Code Playgroud)

v1p*_*p3r 3

选项 1:监听 URL 的变化

由于 SPA 使用路由,因此您可以理想地侦听 url 更改。

一种粗略的方法是使用 setInterval 持续轮询并跟踪 url 的更改。如果 url 已更改,您可以运行您的处理程序。然而,这是浪费的。

由于缺少选项,您可以监听所有可能导致转换的事件(例如鼠标单击、键盘 Enter/Space 键按下等),并在处理程序中检查 url 是否已更改。使用 requestAnimationFrame 以便我们不会过早执行处理程序。

let currentUrl = location.href;
const checkPageTransition = () => {
    requestAnimationFrame(() => {
        if (currentUrl !== location.href) {
            console.log("url changed");
        }
        currentUrl = location.href;
    }, true);
};


document.body.addEventListener("click", checkPageTransition);
document.body.addEventListener("keyup", e => {
    if (e.code === "Enter" || e.code === "Space") checkPageTransition()
});
Run Code Online (Sandbox Code Playgroud)

选项2:监听popstate事件

如果您使用现代 SPA,它们很可能会使用history.pushState 和history.popState 来管理路由。然后我们可以监听 window.popstate 事件。但本次活动也有局限性。

来自: https: //developer.mozilla.org/en-US/docs/Web/API/WindowEventHandlers/onpopstate

注意:调用history.pushState()或history.replaceState()不会触发popstate事件。popstate 事件仅通过执行浏览器操作来触发,例如在同一文档的两个历史记录条目之间导航时单击后退按钮(或在 JavaScript 中调用history.back())。

然而,我们可以猴子修补history.pushState函数,以便它始终触发history.onpushstate函数。

(function(history) { 
    var pushState = history.pushState; 
    history.pushState = function(state) { 
        if (typeof history.onpushstate == "function") 
        { 
            history.onpushstate({ 
                state: state 
            }); 
        } 
        return pushState.apply(history, arguments); 
    } 
})(window.history); 
Run Code Online (Sandbox Code Playgroud)

您还需要类似地修补replaceState 函数。