web-dev-qa-db-ja.com

window.location.hrefが変更されたときのイベント

ある時点でlocation.hrefを変更するサイトのGreasemonkeyスクリプトを書いています。

window.addEventListenerがページ上で変更されたときに、(window.location.hrefまたは類似のものを介して)イベントを取得するにはどうすればよいですか?また、新しい/変更されたURLを指すドキュメントのDOMへのアクセスも必要です。

私はタイムアウトとポーリングを含む他のソリューションを見てきましたが、可能であればそれを避けたいです。

57
Johan Dahlin

ポップステートイベント

アクティブな履歴エントリが変更されると、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'));
};
60
PHF

ポーリングを避けることはできません。hrefを変更するイベントはありません。

とにかく、船外に出ない限り、インターバルの使用は非常に軽いです。 50msごとにhrefを確認しても、心配していればパフォーマンスに大きな影響はありません。

21
Tatu Ulmanen

拡張機能「任意のメディアを取得」でこのスクリプトを使用し、正常に動作します(youtube case

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

};
15

使用できるデフォルトのonhashchangeイベントがあります。

ここに文書化

そして、次のように使用できます:

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

window.onhashchange = locationHashChanged;

ブラウザが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;
    } );
} () );
9
iSkore

アンロードする前に試しましたか?このイベントは、ページがナビゲーションリクエストに応答する直前に発生し、これには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>

ただし、スクリプトが原因であるか、誰かがクリックしたかどうかにかかわらず、ページから離れるたびにevereが発生することに注意してくださいリンク。あなたの本当の課題は、発生するイベントのさまざまな理由を検出することです。 (これがロジックにとって重要な場合)

7
belugabob

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

2

location.hrefを変更するには2つの方法があります。ページをリロードするlocation.href = "y.html"を記述するか、ページをリロードしない履歴APIを使用できます。最近、最初の実験をたくさんしました。

子ウィンドウを開いて、親ウィンドウから子ページのロードをキャプチャする場合、ブラウザごとに動作が大きく異なります。唯一一般的なのは、古いドキュメントを削除して新しいドキュメントを追加することです。したがって、たとえば、readystatechangeやloadイベントハンドラーを古いドキュメントに追加しても効果はありません。ほとんどのブラウザは、ウィンドウオブジェクトからイベントハンドラも削除します。唯一の例外はFirefoxです。 Karmaランナーを使用するChromeおよびFirefoxでは、unload + next tickを使用すると、読み込み中のreadyStateで新しいドキュメントをキャプチャできます。そのため、たとえば、ロードイベントハンドラーまたはreadystatechangeイベントハンドラーを追加したり、ブラウザーが新しいURIでページをロードしていることをログに記録したりできます。手動テストによるChrome(おそらくGreaseMonkeyも)およびOpera、PhantomJS、IE10、IE11では、読み込み中の状態で新しいドキュメントをキャプチャできません。これらのブラウザでは、unload + next tickはページのloadイベントが発生する数百ミリ秒後にコールバックを呼び出します。遅延は通常100〜300ミリ秒ですが、opera simetimeは次のティックで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を使用する単一ページアプリケーションについて話している場合は、ウィンドウのhashchangeおよびpopstateイベントをそれぞれ使用できます。これらは、同じページにとどまるまで履歴を前後に移動してもキャプチャできます。ドキュメントはそれらによって変更されず、ページは実際にはリロードされません。

1
inf3rno