JavaScriptでURLが変更されているかどうかを確認するにはどうすればよいですか?たとえば、AJAXを使用するGitHubのようなWebサイトは、ページをリロードせずに一意のURLを作成するために、#記号の後にページ情報を追加します。このURLが変更されたかどうかを検出する最良の方法は何ですか?
onload
イベントは再度呼び出されますか?- URLのイベントハンドラーはありますか?
- または、変更を検出するためにURLを毎秒チェックする必要がありますか?
JavaScriptでURLが変更されているかどうかを確認するにはどうすればよいですか?たとえば、AJAXを使用するGitHubのようなWebサイトは、ページをリロードせずに一意のURLを作成するために、#記号の後にページ情報を追加します。このURLが変更されたかどうかを検出する最良の方法は何ですか?
onload
イベントは再度呼び出されますか?locationchange
イベントリスナーを追加できるようにしたかったのです。以下の変更後、次のように実行できるようになります
window.addEventListener('locationchange', function(){
console.log('location changed!');
})
対照的にwindow.addEventListener('hashchange',()=>{})
、URLのハッシュタグの後の部分が変更された場合にのみ起動し、window.addEventListener('popstate',()=>{})
常に機能するとは限りません。
この変更は、Christianの回答と同様に、履歴オブジェクトを変更していくつかの機能を追加します。
デフォルトでは、これらの変更の前にイベントがありますが、、、およびpopstate
のイベントはありません。pushstate
replacestate
これにより、これら3つの関数が変更され、すべてがカスタムlocationchange
イベントを起動して使用できるようになります。またpushstate
、replacestate
これらを使用する場合はイベントも起動されます。
これらは変更です:
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)
置き換えています(現時点では実行されていませんが、内部で実行されます)old
new
old
old
new
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以降で使用できることに注意してください。
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
});
少し調べてから編集してください:
どういうわけか、私は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));
};
現在(2017年1月)、世界中のブラウザの92%からpopstateがサポートされています。
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();
ハッシュ変更イベントリスナーを追加してください!
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
}
この解決策は私のために働いた:
function checkURLchange(){
if(window.location.href != oldURL){
alert("url changed!");
oldURL = window.location.href;
}
}
var oldURL = window.location.href;
setInterval(checkURLchange, 1000);
古い質問ですが、ロケーションバープロジェクトは非常に便利です。
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});
URLの変更を聞くには、以下を参照してください。
window.onpopstate = function(event) {
console.log("location: " + document.location + ", state: " + JSON.stringify(event.state));
};
特定の条件の後でリスナーを停止/削除する場合は、このスタイルを使用します。
window.addEventListener('popstate', function(e) {
console.log('url changed')
});
同じドメインの別のページにリダイレクトするリンクをクリックすると、これらのいずれも機能しないようです。したがって、私は独自の解決策を作成しました。
let pathname = location.pathname;
window.addEventListener("click", function() {
if (location.pathname != pathname) {
pathname = location.pathname;
// code
}
});
編集:popstateイベントを確認することもできます(ユーザーがページに戻った場合)
window.addEventListener("popstate", function() {
// code
});
幸運をお祈りしています、
微積分
少しクロム拡張をしている間、私は追加の問題で同じ問題に直面しました:時々、ページは変更されますが、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全体はチェックしていないことを考えると、私が見つけた最もクリーンなソリューションです。
以下の答えはここから来ています(古い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"));
});
})();
どのウィンドウイベントも機能していない場合(私の場合は機能していないため)、ルート要素を(非再帰的に)調べる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変更の直後にイベントがトリガーされたことを確認するために、非常に頻繁にチェックする必要があります。
また、タイミングの問題がなくなるため、タイマーよりも信頼性が高い可能性があります。
別のスレッドで実用的な答えが見つかりました:
常に機能するイベントは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)
})
jQueryのアンロード関数を見てください。それはすべてのものを処理します。
https://api.jquery.com/unload/
ユーザーがページから移動すると、unloadイベントがwindow要素に送信されます。これは多くのことの1つを意味する可能性があります。ユーザーは、リンクをクリックしてページを離れるか、アドレスバーに新しいURLを入力した可能性があります。進むボタンと戻るボタンがイベントをトリガーします。ブラウザウィンドウを閉じると、イベントがトリガーされます。ページのリロードでさえ、最初にアンロードイベントを作成します。
$(window).unload(
function(event) {
alert("navigating");
}
);
window.addEventListener("beforeunload", function (e) {
// do something
}, false);
setInterval
あなたは前の呼び出しをキャンセルすることなく、各呼び出しで新しいものを始めています-おそらくあなたはsetTimeout
これを作成しました。引数として関数を追加するだけで、リンクに変更が加えられるたびに、新旧の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);
};
楽しみ!
var previousUrl = '';
var observer = new MutationObserver(function(mutations) {
if (location.href !== previousUrl) {
previousUrl = location.href;
console.log(`URL changed to ${location.href}`);
}
});
これを行うもう1つの簡単な方法は、クリックイベントを追加し、クラス名を介してページのアンカータグにクリックされたことを検出することです。次に、window.location.hrefを使用してURLデータを取得できます。サーバーへのajaxリクエストを実行するために使用できます。シンプルで簡単。
hashchange
タイトルのためにここに来ましたが、イベント(で利用可能)を聞くことwindow
は解決策ではありませんでした。
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
別の内部をラップします。function
oldPushFunc
oldReplaceFunc
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+).