JavaScript에서 해시 후 URL이 변경되었는지 감지하는 방법


160

JavaScript에서 URL이 변경되었는지 어떻게 확인합니까? 예를 들어 AJAX를 사용하는 GitHub와 같은 웹 사이트는 # 기호 뒤에 페이지 정보를 추가하여 페이지를 다시로드하지 않고 고유 한 URL을 만듭니다. 이 URL이 변경되는지 감지하는 가장 좋은 방법은 무엇입니까?

  • 는 IS onload이벤트가 다시 호출?
  • URL에 대한 이벤트 핸들러가 있습니까?
  • 또는 변경 사항을 감지하기 위해 URL을 1 초마다 확인해야합니까?

1
미래 방문자를 위해 2018 년부터 @aljgom하여 새 대답은 최선의 해결책은 다음과 같습니다 stackoverflow.com/a/52809105/151503
Redzarf

답변:


106

최신 브라우저 (IE8 +, FF3.6 +, Chrome)에서는에서 hashchange이벤트를 들을 수 있습니다 window.

일부 구형 브라우저에서는 계속 확인하는 타이머가 필요합니다 location.hash. jQuery를 사용하는 경우 정확히 수행 하는 플러그인 이 있습니다.


132
이것은 내가 이해하는 것처럼 # 기호 (따라서 이벤트 이름) 다음 부분의 변경에만 작동합니까? 질문 제목에 암시 된 것처럼 전체 URL 변경이 아닙니다.
NPC

13
@NPC 전체 URL 변경을위한 핸들러 (앵커 태그없이)?
Neha Choudhary

타임 아웃 이벤트는 거의 필요하지 않습니다. 마우스 및 키보드 이벤트를 사용하여 확인하십시오.
Sjeiti

해시가 아닌 경로가 변경되면 어떻게됩니까?
SuperUberDuper 2014

@SuperUberDuper 사용자가 탐색을 시작하거나 링크 등을 클릭하여 경로가 변경되면 beforeunload이벤트 만 표시됩니다 . 코드가 URL 변경을 시작한 경우 가장 잘 알고 있습니다.
phihag 2014

92

locationchange이벤트 리스너 를 추가하고 싶었습니다 . 아래 수정 후에는 다음과 같이 할 수 있습니다.

window.addEventListener('locationchange', function(){
    console.log('location changed!');
})

대조적으로, window.addEventListener('hashchange',()=>{})URL에서 해시 태그 뒤에있는 부분이 변경되고 window.addEventListener('popstate',()=>{})항상 작동하지 않는 경우에만 실행됩니다 .

Christian의 답변 과 비슷한이 수정은 기록 개체를 수정하여 일부 기능을 추가합니다.

기본적으로 popstate이벤트가 있지만 pushstate및에 대한 이벤트가 없습니다 replacestate.

이렇게하면이 세 가지 기능이 수정되어 모든 사용자 locationchange가 사용할 사용자 지정 이벤트 pushstate와 해당 replacestate이벤트를 사용하려는 경우 이벤트가 발생합니다.

/* These are the modifications: */
history.pushState = ( f => function pushState(){
    var ret = f.apply(this, arguments);
    window.dispatchEvent(new Event('pushstate'));
    window.dispatchEvent(new Event('locationchange'));
    return ret;
})(history.pushState);

history.replaceState = ( f => function replaceState(){
    var ret = f.apply(this, arguments);
    window.dispatchEvent(new Event('replacestate'));
    window.dispatchEvent(new Event('locationchange'));
    return ret;
})(history.replaceState);

window.addEventListener('popstate',()=>{
    window.dispatchEvent(new Event('locationchange'))
});

2
감사합니다
eslamb

정말 고마워요!
Thomas Lang

1
IE에서 이것을 수행하는 방법이 있습니까? 지원하지 않기 때문에 =>
joshuascotton

1
@joshuacotton =>는 화살표 함수가 함수 (F)이 {...}) (F => 함수 FNAME 바꿀 수 {창 함수 FNAME () {...}}
aljgom

1
이것은 매우 유용하며 매력처럼 작동합니다. 이것이 정답입니다.
Kunal Parekh

77

이 코드를 사용하십시오

window.onhashchange = function() { 
     //code  
}

jQuery와 함께

$(window).bind('hashchange', function() {
     //code
});

7
이것은 답변으로 표시되어야합니다. 한 줄이며 브라우저 이벤트 모델을 사용하며 끝없는 리소스 소비 시간 제한에 의존하지 않습니다
Nick Mitchell

1
이것은 제 생각에 가장 좋은 대답입니다. 플러그인 없음 및 최소 코드
agDev

14
Slack에 의해 구현 된 것과 같이 매우 인기있는 것으로 보이는 비-해시 URL 변경에는 작동하지 않습니다
NycCompSci

26
URL에 해시가있을 때만 트리거되는 경우 어떻게 이것이 최선의 대답입니까?
Aaron

1
다른 것도 듣고 싶어하는 경우 onhashchange 값을 직접 바꾸는 대신 addEventListener를 사용해야합니다.
broken-e

55

약간의 연구 후에 편집하십시오.

어떻게 든 모질라 문서에있는 문서에 바보가 된 것 같습니다. popstate이벤트 (및 콜백 함수 onpopstate)하는 트리거되지 때마다 pushState()또는 replaceState()코드라고합니다. 따라서 원래 답변은 모든 경우에 적용되지 않습니다.

그러나 @ alpha123에 따라 함수원숭이 패치하여 이를 우회하는 방법이 있습니다 .

var pushState = history.pushState;
history.pushState = function () {
    pushState.apply(history, arguments);
    fireEvents('pushState', arguments);  // Some event-handling function
};

원래 답변

이 질문의 제목이 " URL 변경을 감지하는 방법 "이라는 대답을 감안할 때 해시 앵커뿐만 아니라 전체 경로가 언제 변경되는지 알고 싶은 경우 popstate이벤트를 수신 할 수 있다는 것입니다 .

window.onpopstate = function(event) {
  console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

Mozilla Docs의 popstate에 대한 참조

현재 (2017 년 1 월) 전 세계 브라우저의 92 %에서 popstate지원 됩니다.


11
우리는 여전히 2018 년에 그러한 핵에 의존해야한다는 것을 믿어지지 않습니다.
goat

1
이것은 나의 유스 케이스에서 효과가 있었지만 @goat가 말했듯이 이것에 대한 기본 지원이 없다는 것은 믿기지 않습니다 ...
wasddd_

1
무슨 주장? fireEvents를 어떻게 설정합니까?
SeanMC

2
많은 경우에 이것은 신뢰할 수 없습니다. 예를 들어, 다른 Amazon 제품 변형 (가격 아래 타일)을 클릭하면 URL 변경이 감지되지 않습니다.
thdoan

2
location.back ()를 사용하지 않는 경우이 로컬 호스트 / foo에 로컬 호스트로 / BAA에서 변화를 검출 습관
SuperUberDuper

53

jquery (및 플러그인)를 사용하면 할 수 있습니다

$(window).bind('hashchange', function() {
 /* things */
});

http://benalman.com/projects/jquery-hashchange-plugin/

그렇지 않으면, setInterval을 사용하고 해시 이벤트 (window.location.hash)의 변경을 확인해야합니다.

최신 정보! 간단한 초안

function hashHandler(){
    this.oldHash = window.location.hash;
    this.Check;

    var that = this;
    var detect = function(){
        if(that.oldHash!=window.location.hash){
            alert("HASH CHANGED - new has" + window.location.hash);
            that.oldHash = window.location.hash;
        }
    };
    this.Check = setInterval(function(){ detect() }, 100);
}

var hashDetection = new hashHandler();

(창 위치)의 변화를 감지하고 처리 할 수 ​​있습니까? (jquery없이)
BergP

6
일반 자바 스크립트 리스너를 사용하여 @BergP를 사용할 수 있습니다. window.addEventListener("hashchange", hashChanged);
Ron

1
짧은 시간 간격이 앱에 적합합니까? 즉, 브라우저가 detect()기능 을 실행하는 데 너무 바쁘지 않습니까?
Hasib Mahmud

4
@HasibMahmud, 그 코드는 100ms마다 1 개의 동등 검사를 수행합니다. 방금 브라우저에서 벤치 마크하여 1ms 미만에서 500 개의 동등 검사를 수행 할 수 있습니다. 그 코드는 내 처리 능력의 1/50000을 사용하고 있습니다. 나는 너무 걱정하지 않을 것입니다.
z5h

24

해시 변경 이벤트 리스너를 추가하십시오!

window.addEventListener('hashchange', function(e){console.log('hash changed')});

또는 모든 URL 변경 사항을 청취하려면 다음을 수행하십시오.

window.addEventListener('popstate', function(e){console.log('url changed')});

window.onhashchange에는 한 가지만 존재할 수 있으며 다른 사람의 코드를 덮어 쓸 수 있기 때문에 아래 코드와 같은 것이 좋습니다.

// Bad code example

window.onhashchange = function() { 
     // Code that overwrites whatever was previously in window.onhashchange  
}

1
pop state는 상태를 열 때만 트리거하고, 하나를
누르지 않아야합니다.

8

이 솔루션은 저에게 효과적이었습니다.

var oldURL = "";
var currentURL = window.location.href;
function checkURLchange(currentURL){
    if(currentURL != oldURL){
        alert("url changed!");
        oldURL = currentURL;
    }

    oldURL = window.location.href;
    setInterval(function() {
        checkURLchange(window.location.href);
    }, 1000);
}

checkURLchange();

18
이것은 다소 초보적인 방법입니다. 더 높은 목표를 세울 수 있다고 생각합니다.
Carles Alcolea

8
@CarlesAlcolea에 동의하지만 이것이 오래되었다고 생각하지만 내 경험상 여전히 모든 URL 변경 사항을 100 % 잡는 유일한 방법입니다.
Trev14

5
@ahofmann는 변화 (코멘트를 했어야 편집에) 제안 setIntervalsetTimeout:. "는 checkURLchange () 매 초에 새 통화를 만들 수 있기 때문에, 잠시 후 중단 브라우저를 가져올하여 setInterval ()를 사용에서는 setTimeout () 한 번만 호출되기 때문에 올바른 해결 방법입니다. "
divibisan

이것은 모든 URL 변경 사항을 포착하는 유일한 솔루션이지만 리소스 소비로 인해 다른 솔루션을 찾아야합니다.
ReturnTable

3
또는 setTimeout@divibisan이 제안한 것과 같이 대신 setInterval함수 외부로 이동하십시오 . checkURLchange();또한 선택 사항이됩니다.
aristidesfl

4

오래된 질문이지만 Location-bar 프로젝트는 매우 유용합니다.

var LocationBar = require("location-bar");
var locationBar = new LocationBar();

// listen to all changes to the location bar
locationBar.onChange(function (path) {
  console.log("the current url is", path);
});

// listen to a specific change to location bar
// e.g. Backbone builds on top of this method to implement
// it's simple parametrized Backbone.Router
locationBar.route(/some\-regex/, function () {
  // only called when the current url matches the regex
});

locationBar.start({
  pushState: true
});

// update the address bar and add a new entry in browsers history
locationBar.update("/some/url?param=123");

// update the address bar but don't add the entry in history
locationBar.update("/some/url", {replace: true});

// update the address bar and call the `change` callback
locationBar.update("/some/url", {trigger: true});

nodeJ의 경우 클라이언트 측에서 사용하려면 browserify를 사용해야합니다. 우리는 그렇지 않습니까?
hack4mer

1
아닙니다. 브라우저에서 작동
Ray Booysen

3

URL 변경 사항을 들으려면 아래를 참조하십시오.

window.onpopstate = function(event) {
  console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};

특정 조건 후 리스너를 중지 / 제거하려는 경우이 스타일을 사용하십시오.

window.addEventListener('popstate', function(e) {
   console.log('url changed')
});

2

약간의 크롬 확장을 수행하는 동안 추가 문제와 같은 문제에 직면했습니다. 때로는 페이지가 변경되지만 URL은 변경되지 않습니다.

예를 들어 Facebook 홈페이지로 이동하여 '홈'버튼을 클릭하십시오. 페이지를 다시로드하지만 URL은 변경되지 않습니다 (한 페이지 앱 스타일).

99 %의 시간에 Angular, React, Vue 등과 같은 프레임 워크에서 이러한 이벤트를 얻을 수 있도록 웹 사이트를 개발하고 있습니다.

그러나 Chrome 확장 프로그램 (Vanilla JS)의 경우 URL 변경으로 인해 일반적으로 잡힐 수있는 각 "페이지 변경"에 대해 트리거되는 이벤트를 들어야했지만 때로는 그렇지 않습니다.

내 수제 솔루션은 다음과 같습니다.

listen(window.history.length);
var oldLength = -1;
function listen(currentLength) {
  if (currentLength != oldLength) {
    // Do your stuff here
  }

  oldLength = window.history.length;
  setTimeout(function () {
    listen(window.history.length);
  }, 1000);
}

따라서 기본적으로 창 기록에 적용되는 leoneckert 솔루션은 단일 페이지 앱에서 페이지가 변경 될 때 변경됩니다.

로켓 과학이 아니라 내가 찾은 가장 깨끗한 솔루션입니다. 여기서 정수 동등성을 확인하고 더 큰 객체 또는 전체 DOM이 아닌 것을 고려하십시오.


솔루션은 간단하고 크롬 확장 프로그램에 매우 효과적입니다. 길이 대신 YouTube 동영상 ID를 사용하고 싶습니다. stackoverflow.com/a/3452617/808901
Rod Lima

2
listen (xy)을 호출 할 때마다 새로운 간격이 생성되고 수천 간격으로 끝나기 때문에 setInterval을 사용하지 않아야합니다.
Stef Chäser

1
당신은 내가 알아 차리고 내 게시물을 변경하지 않은 것을 알았습니다. 당시에는 RAM 누수로 인해 Chrome 충돌이 발생했습니다. 댓글 주셔서 감사합니다
Alburkerk

window.history최대 길이는 50입니다 (최소한 Chrome 80 기준). 이 시점 이후에는 window.history.length항상 50을 리턴합니다.이 경우이 메소드는 변경 사항을 인식하지 못합니다.
Collin Krawll

1

jQuery 언로드 기능을보십시오. 모든 것을 처리합니다.

https://api.jquery.com/unload/

언로드 이벤트는 사용자가 페이지를 벗어나 탐색 할 때 창 요소로 전송됩니다. 이것은 많은 것들 중 하나를 의미 할 수 있습니다. 사용자가 링크를 클릭하여 페이지를 떠나거나 주소 표시 줄에 새 URL을 입력했을 수 있습니다. 앞으로 및 뒤로 버튼은 이벤트를 트리거합니다. 브라우저 창을 닫으면 이벤트가 트리거됩니다. 페이지를 다시로드하더라도 먼저 언로드 이벤트가 생성됩니다.

$(window).unload(
    function(event) {
        alert("navigating");
    }
);

2
컨텐츠가 Ajaxed 인 경우, 윈도우를 언로드하지 않고 URL이 변경 될 수 있습니다. 이 스크립트는 URL 변경을 감지하지 못하지만 모든 URL 변경에서 창 언로드가있는 일부 사용자에게는 여전히 도움이 될 수 있습니다.
데보라

@ranbuch 질문과 마찬가지로 이것은 단일 페이지 응용 프로그램이 아닌 페이지에만 적용되며이 이벤트는 URL 변경이 아닌 언로드 창 이벤트 만보고 있습니다.
ncubica

0
window.addEventListener("beforeunload", function (e) {
    // do something
}, false);

11
언로드 이벤트가 트리거되지 않기 때문에 단일 페이지 애플리케이션의 컨텍스트에서는 작동하지 않습니다.
ncubica

0

아래 답변은 여기에서 (오래된 자바 스크립트 구문 (화살표 기능 없음, IE 10 이상 지원)) : https : //.com/a/52809105/9168962

(function() {
  if (typeof window.CustomEvent === "function") return false; // If not IE
  function CustomEvent(event, params) {
    params = params || {bubbles: false, cancelable: false, detail: null};
    var evt = document.createEvent("CustomEvent");
    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
    return evt;
  }
  window.CustomEvent = CustomEvent;
})();

(function() {
  history.pushState = function (f) {
    return function pushState() {
      var ret = f.apply(this, arguments);
      window.dispatchEvent(new CustomEvent("pushState"));
      window.dispatchEvent(new CustomEvent("locationchange"));
      return ret;
    };
  }(history.pushState);
  history.replaceState = function (f) {
    return function replaceState() {
      var ret = f.apply(this, arguments);
      window.dispatchEvent(new CustomEvent("replaceState"));
      window.dispatchEvent(new CustomEvent("locationchange"));
      return ret;
    };
  }(history.replaceState);
  window.addEventListener("popstate", function() {
    window.dispatchEvent(new CustomEvent("locationchange"));
  });
})();

0

이 작업을 수행하는 또 다른 간단한 방법은 페이지의 앵커 태그에 클래스 이름을 통해 클릭 이벤트를 추가하여 클릭 시점을 감지 한 다음 window.location.href를 사용하여 URL 데이터를 가져올 수 있습니다. 서버에 대한 ajax 요청을 실행하는 데 사용할 수 있습니다. 간단하고 쉽습니다.


당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.