[javascript] window.location.href 변경시 이벤트

어느 시점에서 수정하는 사이트에 대한 Greasemonkey 스크립트를 작성 중 location.href입니다.

페이지 window.addEventListenerwindow.location.href변경 될 때 어떻게 이벤트를받을 수 있습니까 ( 또는 이와 유사한 것을 통해 ) ? 또한 새 / 수정 된 URL을 가리키는 문서의 DOM에 대한 액세스가 필요합니다.

시간 초과 및 폴링과 관련된 다른 솔루션을 보았지만 가능하면 피하고 싶습니다.



답변

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


답변

내 확장 프로그램 “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);

};


답변

폴링을 피할 수 없으며 href 변경에 대한 이벤트가 없습니다.

배 밖으로 나가지 않으면 간격을 사용하는 것은 어쨌든 매우 가볍습니다. 50ms 정도마다 href를 확인하는 것이 걱정되는 경우 성능에 큰 영향을 미치지 않습니다.


답변

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


답변

전에 시도해 보셨습니까? 이 이벤트는 페이지가 탐색 요청에 응답하기 직전에 발생하며 여기에는 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>

그러나 스크립트 때문이든 누군가가 링크를 클릭했는지 여부에 관계없이 페이지에서 벗어날 때마다 이벤트가 실행된다는 점에 유의 하십시오. 당신의 진정한 도전은 이벤트가 시작되는 다양한 이유를 감지하는 것입니다. (이것은 당신의 논리에 중요한 경우)


답변

Jquery를 통해 시도하십시오.

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

자바 스크립트 사용 :

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

문서 참조 : https://developer.mozilla.org/en-US/docs/Web/Events/beforeunload


답변

.NET Framework를 변경하는 방법에는 두 가지가 있습니다 location.href. 어느 쪽이든 당신은 쓸 수있는 location.href = "y.html"페이지를 다시로드하거나 페이지를 다시로드하지 않는 역사의 API를 사용할 수있는. 최근에 처음으로 많이 실험했습니다.

자식 창을 열고 부모 창에서 자식 페이지의로드를 캡처하면 다른 브라우저가 매우 다르게 작동합니다. 유일한 공통점은 이전 문서를 제거하고 새 문서를 추가하는 것입니다. 예를 들어 이전 문서에 readystatechange 또는 load 이벤트 핸들러를 추가해도 아무런 효과가 없습니다. 대부분의 브라우저는 창 개체에서도 이벤트 처리기를 제거합니다. 유일한 예외는 Firefox입니다. Karma runner 및 Firefox가있는 Chrome에서 다음을 사용하는 경우 loading readyState에서 새 문서를 캡처 할 수 있습니다.unload + next tick. 따라서 예를 들어로드 이벤트 처리기 또는 readystatechange 이벤트 처리기를 추가하거나 브라우저가 새 URI로 페이지를로드하고 있음을 기록 할 수 있습니다. 수동 테스트 (GreaseMonkey도 가능)를 사용하는 Chrome과 Opera, PhantomJS, IE10, IE11에서는로드 상태에서 새 문서를 캡처 할 수 없습니다. 이러한 브라우저 unload + next tick에서 페이지의로드 이벤트가 발생하는 것보다 수백 msec 후에 콜백을 호출합니다. 지연은 일반적으로 100 ~ 300msec이지만 Opera simetime은 다음 틱에 대해 750msec 지연을 만들어 무섭습니다. 따라서 모든 브라우저에서 일관된 결과를 원하면로드 이벤트 후에 원하는 작업을 수행하지만 그 전에 위치가 재정의되지 않을 것이라는 보장은 없습니다.

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창의 이벤트를 사용할 수 있습니다 . 동일한 페이지에 머물 때까지 역사에서 앞뒤로 이동하더라도 캡처 할 수 있습니다. 문서는 변경되지 않으며 페이지는 실제로 다시로드되지 않습니다.