Событие при изменении window.location.href - PullRequest
54 голосов
/ 19 августа 2010

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

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

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

Ответы [ 7 ]

58 голосов
/ 12 ноября 2015

событие 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'));
};
21 голосов
/ 19 августа 2010

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

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

12 голосов
/ 26 сентября 2017

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

};
9 голосов
/ 12 апреля 2017

По умолчанию 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;
    } );
} () );
7 голосов
/ 19 августа 2010

Вы пробовали до загрузки? Это событие запускается непосредственно перед тем, как страница отвечает на запрос навигации, и это должно включать изменение 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>

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

2 голосов
/ 06 марта 2018

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

1 голос
/ 18 августа 2018

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

...