Подтвердить что ты не робот

Событие при изменении window.location.href

Я пишу Greasemonkey script для сайта, который в какой-то момент модифицирует location.href.

Как я могу получить событие (через window.addEventListener или что-то подобное), когда window.location.href изменяется на странице? Мне также нужен доступ к DOM документа, указывающего на новый/измененный URL.

Я видел другие решения, которые включают тайм-ауты и опросы, но я хотел бы избежать этого, если это возможно.

4b9b3361

Ответ 1

событие popstate:

Событие popstate запускается при изменении активной записи истории. [...] Событие popstate запускается только с помощью действия браузера, такого как щелчок по кнопке "Назад" (или вызов history.back() в JavaScript)

Итак, при прослушивании события popstate и отправке события popstate при использовании history.pushState() должно быть достаточно, чтобы принять меры при изменении href:

window.addEventListener('popstate', listener);

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

Ответ 2

Вы не можете избежать опроса, нет никакого события для изменения href.

Использование интервалов довольно легко, если вы не заходите за борт. Проверка href каждые 50 мс или около того не окажет существенного влияния на производительность, если вы беспокоитесь об этом.

Ответ 3

Я использую этот script в своем расширении "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);

};

Ответ 4

Существует событие 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;
    } );
} () );

Ответ 5

Вы пробовали 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>

Остерегайтесь, однако, что ваше событие будет срабатывать при, если вы перейдете от страницы, будь то из-за script или кого-либо, щелкнувшего ссылку. Ваша настоящая проблема - это выявление различных причин для увольнения. (Если это важно для вашей логики)

Ответ 6

Через 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

Ответ 7

Ну, есть 2 способа изменить location.href. Либо вы можете написать location.href= "y.html", который перезагружает страницу, либо можете использовать API истории, который не перезагружает страницу. Я впервые много экспериментировал с первым.

Если вы открываете дочернее окно и фиксируете загрузку дочерней страницы из родительского окна, то разные браузеры ведут себя очень по-разному. Единственное, что является общим, это то, что они удаляют старый документ и добавляют новый, поэтому, например, добавление обработчиков событий readystatechange или load в старый документ не имеет никакого эффекта. Большинство браузеров также удаляют обработчики событий из объекта окна, единственным исключением является Firefox. В Chrome с Karma Runner и в Firefox вы можете захватить новый документ в загрузке readyState, если вы используете unload + next tick. Таким образом, вы можете добавить, например, обработчик события загрузки или обработчик события readystatechange, или просто зарегистрировать, что браузер загружает страницу с новым URI. В Chrome с ручным тестированием (возможно, и в GreaseMonkey) и в Opera, PhantomJS, IE10, IE11 вы не можете захватить новый документ в состоянии загрузки. В этих браузерах unload + next tick вызывает обратный вызов на несколько сотен мсек позже, чем событие загрузки страницы. Задержка, как правило, составляет от 100 до 300 мсек, но время оперы делает задержку 750 мсек для следующего такта, что пугает. Поэтому, если вы хотите получить стабильный результат во всех браузерах, то вы делаете то, что хотите после события загрузки, но нет гарантии, что местоположение не будет переопределено до этого.

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 окна соответственно. Они могут захватывать, даже если вы перемещаетесь в истории назад и вперед, пока не останетесь на той же странице. Документ не изменяется, и страница не перезагружается.