javascript 当窗口.位置.href更改时的事件

tnkciper  于 2022-12-25  发布在  Java
关注(0)|答案(9)|浏览(289)

我正在为一个站点编写一个Greasemonkey脚本,该站点在某个时候修改location.href
window.location.href在一个页面上发生变化时,我如何获得一个事件(通过window.addEventListener或类似的东西)?我还需要访问指向新的/修改后的url的文档的DOM。
我见过其他涉及超时和轮询的解决方案,但如果可能的话,我希望避免这种情况。

hjqgdpho

hjqgdpho1#

我在我的扩展中使用这个脚本“抓取任何媒体”,工作很好(* 像YouTube案例 *)

var oldHref = document.location.href;

window.onload = function() {
    var bodyList = document.querySelector("body")

    var 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);
};

使用最新的javascript规范

const observeUrlChange = () => {
const oldHref = document.location.href;
const body = document.querySelector("body");
const observer = new MutationObserver(mutations => {
    mutations.forEach(() => {
      if (oldHref !== document.location.href) {
        oldHref = document.location.href;
        /* Changed ! your code here */
      }
    });
  });
  observer.observe(body, { childList: true, subtree: true });
};

window.onload = observeUrlChange;

用OpenAI压缩

window.onload = () => new MutationObserver(mutations => mutations.forEach(() => oldHref !== document.location.href && (oldHref = document.location.href, /* Changed ! your code here */))).observe(document.querySelector("body"), { childList: true, subtree: true });
7kqas0il

7kqas0il2#

popstate event
popstate事件在活动的历史条目发生变化时被激发。[...] popstate事件只会通过执行浏览器操作来触发,比如点击后退按钮(或者在JavaScript中调用history. back())
因此,在使用history.pushState()时侦听popstate事件并发送popstate事件应足以对href更改采取操作:

window.addEventListener('popstate', listener);

const pushUrl = (href) => {
  history.pushState({}, '', href);
  window.dispatchEvent(new Event('popstate'));
};
vlju58qv

vlju58qv3#

您无法避免轮询,因为没有任何href更改事件。
如果你不过分的话,使用间隔是很轻的。如果你担心的话,每50ms左右检查一次href不会对性能有任何显著的影响。

n6lpvg4x

n6lpvg4x4#

您可以使用默认的onhashchange事件。
Documented HERE
并且可以像这样使用:

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

window.onhashchange = locationHashChanged;

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

//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;
    } );
} () );
nnt7mjpx

nnt7mjpx5#

通过Jquery,只需尝试

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

通过使用javascript

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

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

qrjkbowd

qrjkbowd6#

您是否尝试过beforeUnload?此事件在页面响应导航请求之前立即触发,这应该包括对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>

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

n9vozmp4

n9vozmp47#

试试这个脚本,它可以让你在URL改变时运行代码(没有页面加载,就像单页应用程序一样):

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

jgovgodb8#

有两种方法可以修改location.href。要么你可以写location.href = "y.html",它会重新加载页面,要么你可以使用历史API,它不会重新加载页面。我最近经常尝试第一种方法。
如果你打开一个子窗口并从父窗口获取子页面的负载,那么不同的浏览器的行为会有很大的不同。唯一的共同点是,它们会删除旧文档并添加一个新文档,因此,例如,向旧文档添加readystatechange或load事件处理程序没有任何效果。大多数浏览器也会从window对象中删除事件处理程序,唯一的例外是Firefox。在带有Karma runner的Chrome和Firefox中,如果使用unload + next tick,则可以在加载readyState中捕获新文档。因此,您可以添加一个load事件处理程序或readystatechange事件处理程序,或者只记录浏览器正在加载带有新URI的页面。在带有手动测试的Chrome中(可能也是GreaseMonkey),而在Opera、PhantomJS、IE10、IE11中,您无法在加载状态下捕获新文档。在这些浏览器中,unload + next tick调用回调的时间比页面的加载事件触发时间晚几百毫秒。延迟通常为100到300毫秒。但是opera simetime在下一个tick时会有750毫秒的延迟,这是很可怕的,所以如果你想在所有浏览器中得到一致的结果,那么你可以在load事件之后做你想做的事情,但是不能保证在此之前位置不会被覆盖。

var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");

var callBacks = [];
var uglyHax = function (){
    var done = function (){
        uglyHax();
        callBacks.forEach(function (cb){
            cb();
        });
    };
    win.addEventListener("unload", function unloadListener(){
        win.removeEventListener("unload", unloadListener); // Firefox remembers, other browsers don't
        setTimeout(function (){
            // IE10, IE11, Opera, PhantomJS, Chrome has a complete new document at this point
            // Chrome on Karma, Firefox has a loading new document at this point
            win.document.readyState; // IE10 and IE11 sometimes fails if I don't access it twice, idk. how or why
            if (win.document.readyState === "complete")
                done();
            else
                win.addEventListener("load", function (){
                    setTimeout(done, 0);
                });
        }, 0);
    });
};
uglyHax();

callBacks.push(function (){
    console.log("cb", win.location.href, win.document.readyState);
    if (win.location.href !== "http://localhost:4444/y.html")
        win.location.href = "http://localhost:4444/y.html";
    else
        console.log("done");
});
win.location.href = "http://localhost:4444/x.html";

如果您只在Firefox中运行脚本,那么您可以使用简化版本并在加载状态下捕获文档,例如,在您记录URI更改之前,加载页面上的脚本无法导航离开:

var uuid = "win." + Math.random();
var timeOrigin = new Date();
var win = window.open("about:blank", uuid, "menubar=yes,location=yes,resizable=yes,scrollbars=yes,status=yes");

var callBacks = [];
win.addEventListener("unload", function unloadListener(){
    setTimeout(function (){
        callBacks.forEach(function (cb){
            cb();
        });
    }, 0);
});

callBacks.push(function (){
    console.log("cb", win.location.href, win.document.readyState);
    // be aware that the page is in loading readyState, 
    // so if you rewrite the location here, the actual page will be never loaded, just the new one
    if (win.location.href !== "http://localhost:4444/y.html")
        win.location.href = "http://localhost:4444/y.html";
    else
        console.log("done");
});
win.location.href = "http://localhost:4444/x.html";

如果我们讨论的是改变URI哈希部分的单页应用程序,或者使用历史API,那么你可以分别使用窗口的hashchangepopstate事件。即使你在历史中来回移动,直到你停留在同一页,这些事件也可以捕获。文档不会被这些事件改变,页面也不会被真正重新加载。

nzkunb0c

nzkunb0c9#

根据“列奥纳多Ciaccio”的答案,修改后的代码如下所示:即删除for循环,如果删除,则重新分配Body元素

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

相关问题