window.location.href更改时的事件

Joh*_*lin 62 javascript dom greasemonkey dom-events

我正在为一个网站编写Greasemonkey脚本,该脚本在某些时候会修改location.href.

如何在页面上进行更改window.addEventListener时获得事件(通过或类似的东西)window.location.href?我还需要访问指向新/修改的URL的文档的DOM.

我已经看到了其他涉及超时和轮询的解决方案,但我想尽可能避免这种情况.

PHF*_*PHF 70

popstate事件:

当活动历史记录条目更改时,将触发popstate事件.[...] popstate事件只能通过执行浏览器操作来触发,例如单击后退按钮(或在JavaScript中调用history.back())

因此,在使用时收听popstate事件并发送popstate事件history.pushState()应该足以对href变更采取行动:

window.addEventListener('popstate', listener);

const pushUrl = (href) => {
  history.pushState({}, '', href);
  window.dispatchEvent(new Event('popstate'));
};
Run Code Online (Sandbox Code Playgroud)

  • 如果对“pushState”的代码片段没有任何控制,则无法使用 (13认同)
  • 这并不总是有效,它依赖于要触发的 popstate 事件。例如,在 YouTube 中导航,只有在历史记录中按后退或前进时,它才不会触发 (3认同)
  • 但是在加载内容之前 popstate 会触发吗? (2认同)

law*_*itt 31

在支持的浏览器中,使用新的导航 API,该 API 目前正在实现作为历史记录 API 的替代品:

navigation.addEventListener('navigate', () => {
  console.log('page changed');
});
Run Code Online (Sandbox Code Playgroud)

这已经在 Chromium 浏览器中运行,但截至 2024 年 1 月,Firefox 和 Safari 目前还缺少它。

它大大简化了问题,并且是专门针对单页应用程序而设计的,这是现有解决方案的主要痛点。不再有令人讨厌的昂贵MutationObserver电话!


小智 24

我在我的扩展程序"Grab Any Media"中使用此脚本并正常工作(如youtube案例)

var oldHref = document.location.href;

window.onload = function() {

    var
         bodyList = document.querySelector("body")

        ,observer = new MutationObserver(function(mutations) {

            mutations.forEach(function(mutation) {

                if (oldHref != document.location.href) {

                    oldHref = document.location.href;

                    /* Changed ! your code here */

                }

            });

        });

    var config = {
        childList: true,
        subtree: true
    };

    observer.observe(bodyList, config);

};
Run Code Online (Sandbox Code Playgroud)

  • 开箱即用,对我的用例来说没有任何麻烦,上帝保佑!令人烦恼的是,目前还没有针对此的本地事件(popstate 对我不起作用),但是有一天!我会使用 `window.addEventListener("load", () => {})` 而不是 window.onload :) (3认同)
  • 这是解决这个问题最聪明的方法(聆听身体的变化)。也可以在 React 中工作以检测 URL 更改。多谢! (2认同)
  • 您好,我是 MutationObservers 的新手,并且喜欢这个解决方案,这是我发现迄今为止唯一适用于 YT 重定向的解决方案。只是想指出,您可以通过在“forEach”调用之前移动“if (oldHref != document.location.href)”检查来提高效率,因为您只需要执行一次检查。 (2认同)

Tat*_*nen 23

您无法避免轮询,href更改没有任何事件.

如果你不过分,使用间隔是相当轻的.如果你担心的话,每50ms左右检查一次href对性能没有任何重大影响.

  • 不幸的是,这个答案在 2020 年仍然是正确的。 [popstate 仅在用户使用前进/后退按钮时触发](/sf/answers/990554351/) 而 hashchange 仅在哈希更改时触发。除非您可以控制导致位置更改的代码,否则您必须轮询‍♀️ (8认同)
  • @AlexanderMills:幸运的是,有这些`popstate` 和`hashchange` 的新解决方案。 (4认同)
  • 这不是真的。 (2认同)

iSk*_*ore 10

onhashchange您可以使用 默认事件.

记录在这里

并且可以像这样使用:

function locationHashChanged( e ) {
    console.log( location.hash );
    console.log( e.oldURL, e.newURL );
    if ( location.hash === "#pageX" ) {
        pageX();
    }
}

window.onhashchange = locationHashChanged;
Run Code Online (Sandbox Code Playgroud)

如果浏览器不支持oldURL,newURL您可以像这样绑定它:

//let this snippet run before your hashChange event binding code
if( !window.HashChangeEvent )( function() {
    let lastURL = document.URL;
    window.addEventListener( "hashchange", function( event ) {
        Object.defineProperty( event, "oldURL", { enumerable: true, configurable: true, value: lastURL } );
        Object.defineProperty( event, "newURL", { enumerable: true, configurable: true, value: document.URL } );
        lastURL = document.URL;
    } );
} () );
Run Code Online (Sandbox Code Playgroud)

  • 仅当您的URL的部分以“#”符号开头(通常用于锚链接)时,才会发送Hashchange事件。否则它将不会触发。 (5认同)

小智 8

通过Jquery,试试

$(window).on('beforeunload', function () {
    //your code goes here on location change 
});
Run Code Online (Sandbox Code Playgroud)

通过使用javascript

window.addEventListener("beforeunload", function (event) {
   //your code goes here on location change 
});
Run Code Online (Sandbox Code Playgroud)

参考文档:https : //developer.mozilla.org/en-US/docs/Web/Events/beforeunload


bel*_*bob 7

你有没有尝试过卸载?此事件在页面响应导航请求之前立即触发,这应包括修改href.

    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">
    <HTML>
    <HEAD>
    <TITLE></TITLE>
    <META NAME="Generator" CONTENT="TextPad 4.6">
    <META NAME="Author" CONTENT="?">
    <META NAME="Keywords" CONTENT="?">
    <META NAME="Description" CONTENT="?">
    </HEAD>

         <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
            <script type="text/javascript">
            $(document).ready(function(){
                $(window).unload(
                        function(event) {
                            alert("navigating");
                        }
                );
                $("#theButton").click(
                    function(event){
                        alert("Starting navigation");
                        window.location.href = "http://www.bbc.co.uk";
                    }
                );

            });
            </script>


    <BODY BGCOLOR="#FFFFFF" TEXT="#000000" LINK="#FF0000" VLINK="#800000" ALINK="#FF00FF" BACKGROUND="?">

        <button id="theButton">Click to navigate</button>

        <a href="http://www.google.co.uk"> Google</a>
    </BODY>
    </HTML>
Run Code Online (Sandbox Code Playgroud)

但是,请注意,无论是因为脚本还是有人点击链接,您的事件都会您离开页面触发.您真正面临的挑战是检测事件被触发的不同原因.(如果这对你的逻辑很重要)


d-_*_*_-b 7

尝试这个脚本,它可以让您在 URL 更改时运行代码(无需页面加载,如单页面应用程序):

var previousUrl = '';
var observer = new MutationObserver(function(mutations) {
  if (location.href !== previousUrl) {
      previousUrl = location.href;
      console.log(`URL changed to ${location.href}`);
    }
});
Run Code Online (Sandbox Code Playgroud)


zem*_*mil 7

ReactJS 和其他 SPA应用程序使用该history对象

可以window.history通过以下代码监听更新:

function watchHistoryEvents() {
    const { pushState, replaceState } = window.history;

    window.history.pushState = function (...args) {
        pushState.apply(window.history, args);
        window.dispatchEvent(new Event('pushState'));
    };

    window.history.replaceState = function (...args) {
        replaceState.apply(window.history, args);
        window.dispatchEvent(new Event('replaceState'));
    };

    window.addEventListener('popstate', () => console.log('popstate event'));
    window.addEventListener('replaceState', () => console.log('replaceState event'));
    window.addEventListener('pushState', () => console.log('pushState event'));
}
watchHistoryEvents();
Run Code Online (Sandbox Code Playgroud)


Che*_*ung 6

根据“Leonardo Ciaccio”的答案,修改后的代码在这里:即删除 for 循环并重新分配 Body 元素(如果删除)

window.addEventListener("load", function () {
  let oldHref = document.location.href,
    bodyDOM = document.querySelector("body");
  function checkModifiedBody() {
    let tmp = document.querySelector("body");
    if (tmp != bodyDOM) {
      bodyDOM = tmp;
      observer.observe(bodyDOM, config);
    }
  }
  const observer = new MutationObserver(function (mutations) {
    if (oldHref != document.location.href) {
      oldHref = document.location.href;
      console.log("the location href is changed!");
      window.requestAnimationFrame(checkModifiedBody)
    }
  });
  const config = {
    childList: true,
    subtree: true
  };
  observer.observe(bodyDOM, config);
}, false);
Run Code Online (Sandbox Code Playgroud)