211

JavaScriptでURLが変更されているかどうかを確認するにはどうすればよいですか?たとえば、AJAXを使用するGitHubのようなWebサイトは、ページをリロードせずに一意のURLを作成するために、#記号の後にページ情報を追加します。このURLが変更されたかどうかを検出する最良の方法は何ですか?

  • onloadイベントは再度呼び出されますか?
  • URLのイベントハンドラーはありますか?
  • または、変更を検出するためにURLを毎秒チェックする必要がありますか?
4

21 に答える 21

181

locationchangeイベントリスナーを追加できるようにしたかったのです。以下の変更後、次のように実行できるようになります

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

対照的にwindow.addEventListener('hashchange',()=>{})、URLのハッシュタグの後の部分が変更された場合にのみ起動し、window.addEventListener('popstate',()=>{})常に機能するとは限りません。

この変更は、Christianの回答と同様に、履歴オブジェクトを変更していくつかの機能を追加します。

デフォルトでは、これらの変更の前にイベントがありますが、、、およびpopstateのイベントはありません。pushstatereplacestate

これにより、これら3つの関数が変更され、すべてがカスタムlocationchangeイベントを起動して使用できるようになります。またpushstatereplacestateこれらを使用する場合はイベントも起動されます。

これらは変更です:

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

ノート:

クロージャを作成しており、以前に保存された関数を含む関数にold = (f=>function new(){f();...})(old)置き換えています(現時点では実行されていませんが、内部で実行されます)oldnewoldoldnew

于 2018-10-15T02:47:34.387 に答える
129

hashchange最新のブラウザ(IE8 +、FF3.6 +、Chrome)では、でイベントを聞くことができますwindow

一部の古いブラウザでは、継続的にチェックするタイマーが必要ですlocation.hash。jQueryを使用している場合は、まさにそれを実行するプラグインがあります。

以下では、スクロールだけを続けるために、URLの変更を元に戻します。

<script type="text/javascript">
  if (window.history) {
    var myOldUrl = window.location.href;
    window.addEventListener('hashchange', function(){
      window.history.pushState({}, null, myOldUrl);
    });
  }
</script>

上記で使用されているhistory-APIは、Chrome、Safari、Firefox 4以降、およびInternetExplorer10pp4以降で使用できることに注意してください。

于 2011-06-17T18:50:19.050 に答える
94
window.onhashchange = function() { 
     //code  
}

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

また

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

window.addEventListener('popstate', function() { 
  //code  
});

jQueryを使用

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

$(window).bind('popstate', function() {
     //code
});
于 2016-05-07T17:18:36.000 に答える
72

少し調べてから編集してください:

どういうわけか、私はMozillaドキュメントにあるドキュメントにだまされたようです。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));
};

MozillaDocsのpopstateのリファレンス

現在(2017年1月)、世界中のブラウザの92%からpopstateがサポートされています。

于 2017-01-24T09:56:54.077 に答える
52

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();
于 2011-06-17T18:49:20.143 に答える
27

ハッシュ変更イベントリスナーを追加してください!

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

または、すべてのURL変更をリッスンするには:

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

これは、window.onhashchangeに存在できるものが1つだけであり、他の誰かのコードを上書きする可能性があるため、以下のコードのようなものよりも優れています。

// Bad code example

window.onhashchange = function() { 
     // Code that overwrites whatever was previously in window.onhashchange  
}
于 2017-06-01T23:26:27.073 に答える
9

この解決策は私のために働いた:

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

var oldURL = window.location.href;
setInterval(checkURLchange, 1000);
于 2016-04-05T23:37:20.917 に答える
4

古い質問ですが、ロケーションバープロジェクトは非常に便利です。

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});
于 2015-05-20T14:14:20.893 に答える
4

URLの変更を聞くには、以下を参照してください。

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

特定の条件の後でリスナーを停止/削除する場合は、このスタイルを使用します。

window.addEventListener('popstate', function(e) {
   console.log('url changed')
});
于 2017-12-20T09:01:47.293 に答える
3

同じドメインの別のページにリダイレクトするリンクをクリックすると、これらのいずれも機能しないようです。したがって、私は独自の解決策を作成しました。

let pathname = location.pathname;
window.addEventListener("click", function() {
    if (location.pathname != pathname) {
        pathname = location.pathname;
        // code
    }
});

編集:popstateイベントを確認することもできます(ユーザーがページに戻った場合)

window.addEventListener("popstate", function() {
    // code
});

幸運をお祈りしています、

微積分

于 2021-07-14T03:32:40.027 に答える
2

少しクロム拡張をしている間、私は追加の問題で同じ問題に直面しました:時々、ページは変更されますが、URLは変更されません。

たとえば、Facebookのホームページに移動し、[ホーム]ボタンをクリックします。ページをリロードしますが、URLは変更されません(1ページのアプリスタイル)。

99%の時間、Angular、React、Vueなどのフレームワークからそれらのイベントを取得できるようにWebサイトを開発しています。

しかし、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全体はチェックしていないことを考えると、私が見つけた最もクリーンなソリューションです。

于 2018-04-11T10:27:25.323 に答える
2

以下の答えはここから来ています(古いjavascript構文(矢印関数なし、IE 10以降をサポート)): https ://stackoverflow.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"));
  });
})();
于 2019-08-21T08:06:11.977 に答える
2

どのウィンドウイベントも機能していない場合(私の場合は機能していないため)、ルート要素を(非再帰的に)調べるMutationObserverを使用することもできます。

// capture the location at page load
let currentLocation = document.location.href;

const observer = new MutationObserver((mutationList) => {
  if (currentLocation !== document.location.href) {
    // location changed!
    currentLocation = document.location.href;

    // (do your event logic here)
  }
});

observer.observe(
  document.getElementById('root'),
  {
    childList: true,

    // important for performance
    subtree: false
  });

これは常に実行可能であるとは限りませんが、通常、URLが変更されると、ルート要素のコンテンツも変更されます。

私はプロファイルを作成していませんが、理論的には、オブザーバーパターンは変更が発生したときにサブスクリプションをループするように実装されているため、タイマーよりもオーバーヘッドが少なくなります。ここではサブスクリプションを1つだけ追加しました。一方、タイマーは、URL変更の直後にイベントがトリガーされたことを確認するために、非常に頻繁にチェックする必要があります。

また、タイミングの問題がなくなるため、タイマーよりも信頼性が高い可能性があります。

于 2021-03-20T15:35:13.610 に答える
1

別のスレッドで実用的な答えが見つかりました:

常に機能するイベントは1つではなく、pushStateイベントにパッチを適用するモンキーパッチは、ほとんどの主要なSPAでかなりヒットまたはミスします。

したがって、スマートポーリングは、私にとって最も効果的な方法です。イベントタイプはいくつでも追加できますが、これらは私にとって本当に良い仕事をしているようです。

TS用に書かれていますが、簡単に変更できます。

const locationChangeEventType = "MY_APP-location-change";

// called on creation and every url change
export function observeUrlChanges(cb: (loc: Location) => any) {
  assertLocationChangeObserver();
  window.addEventListener(locationChangeEventType, () => cb(window.location));
  cb(window.location);
}

function assertLocationChangeObserver() {
  const state = window as any as { MY_APP_locationWatchSetup: any };
  if (state.MY_APP_locationWatchSetup) { return; }
  state.MY_APP_locationWatchSetup = true;

  let lastHref = location.href;

  ["popstate", "click", "keydown", "keyup", "touchstart", "touchend"].forEach((eventType) => {
    window.addEventListener(eventType, () => {
      requestAnimationFrame(() => {
        const currentHref = location.href;
        if (currentHref !== lastHref) {
          lastHref = currentHref;
          window.dispatchEvent(new Event(locationChangeEventType));
        }
      })
    })
  });
}

使用法

observeUrlChanges((loc) => {
  console.log(loc.href)
})
于 2020-10-06T19:20:02.417 に答える
0

jQueryのアンロード関数を見てください。それはすべてのものを処理します。

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

ユーザーがページから移動すると、unloadイベントがwindow要素に送信されます。これは多くのことの1つを意味する可能性があります。ユーザーは、リンクをクリックしてページを離れるか、アドレスバーに新しいURLを入力した可能性があります。進むボタンと戻るボタンがイベントをトリガーします。ブラウザウィンドウを閉じると、イベントがトリガーされます。ページのリロードでさえ、最初にアンロードイベントを作成します。

$(window).unload(
    function(event) {
        alert("navigating");
    }
);
于 2016-01-06T16:30:00.530 に答える
0
window.addEventListener("beforeunload", function (e) {
    // do something
}, false);
于 2016-05-01T12:14:09.943 に答える
0

setIntervalあなたは前の呼び出しをキャンセルすることなく、各呼び出しで新しいものを始めています-おそらくあなたはsetTimeout

于 2017-01-26T13:00:18.697 に答える
0

これを作成しました。引数として関数を追加するだけで、リンクに変更が加えられるたびに、新旧のURLを返す関数が実行されます。

これを作成しました。引数として関数を追加するだけで、リンクに変更が加えられるたびに、新旧のURLを返す関数が実行されます。

// on-url-change.js v1 (manual verification)
let onUrlChangeCallbacks = [];
let onUrlChangeTimestamp = new Date() * 1;
function onUrlChange(callback){
    onUrlChangeCallbacks.push(callback);
};
onUrlChangeAutorun();
function onUrlChangeAutorun(){
    let oldURL = window.location.href;
    setInterval(function(){
        let newURL = window.location.href;
        if(oldURL !== newURL){
            let event = {
                oldURL: oldURL,
                newURL: newURL,
                type: 'urlchange',
                timestamp: new Date() * 1 - onUrlChangeTimestamp
            };
            oldURL = newURL;
            for(let i = 0; i < onUrlChangeCallbacks.length; i++){
                onUrlChangeCallbacks[i](event);
            };
        };
    }, 25);
};
于 2020-11-03T14:33:20.490 に答える
0

楽しみ!

var previousUrl = '';
var observer = new MutationObserver(function(mutations) {
  if (location.href !== previousUrl) {
      previousUrl = location.href;
      console.log(`URL changed to ${location.href}`);
    }
});
于 2021-06-03T14:04:21.737 に答える
-1

これを行うもう1つの簡単な方法は、クリックイベントを追加し、クラス名を介してページのアンカータグにクリックされたことを検出することです。次に、window.location.hrefを使用してURLデータを取得できます。サーバーへのajaxリクエストを実行するために使用できます。シンプルで簡単。

于 2020-04-02T14:04:54.957 に答える
-1

hashchangeタイトルのためにここに来ましたが、イベント(で利用可能)を聞くことwindowは解決策ではありませんでした。

まず、以下が1回実行されることを確認します。

history.pushState = (function (oldPushFunc) {
    return function () {
        var ret = oldPushFunc.apply(this, arguments);
        window.dispatchEvent(new Event('pushstate'));
        window.dispatchEvent(new Event('myUrlChangeEvent'));
        return ret;
    };
})(history.pushState);

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

window.addEventListener('popstate', function () {
    window.dispatchEvent(new Event('myUrlChangeEvent'));
});

上記は、グローバル変数をスパムせずに通過するClousorを作成するために、function別の内部をラップします。functionoldPushFuncoldReplaceFunc

最後に、作成したカスタムイベントを使用します

window.addEventListener('myUrlChangeEvent', function () {
    console.log('URL did change!');
});

Note that above used history-API is available in all modern browsers, like, Chrome, Safari, Firefox 4+, and Internet Explorer 10pp4+).

于 2022-01-27T17:14:13.157 に答える